diff --git a/.Rbuildignore b/.Rbuildignore
index d01e70c..51c3245 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -11,5 +11,6 @@
^\.lintr$
^tools$
^pkgdown-site$
-^data/(bairro2APS|locs|sinan)\.rda$
+^consumer-evidence$
^inla-evidence$
+^data/(bairro2APS|locs|sinan)\.rda$
diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index c4a36ce..2bb4be5 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -87,8 +87,14 @@ jobs:
extra-packages: any::devtools
needs: check
- - name: Run the complete suite against ephemeral PostgreSQL
- run: Rscript -e 'devtools::test(stop_on_failure = TRUE)'
+ - name: Run the package and pinned consumer suite against PostgreSQL
+ run: Rscript tools/run-postgres-integration.R consumer-evidence
+
+ - uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: consumer-compatibility-evidence
+ path: consumer-evidence/
inla-integration:
runs-on: ubuntu-latest
diff --git a/NEWS.md b/NEWS.md
index bced05a..461f293 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,21 @@
## Review follow-up
+- Sort each municipality-disease series chronologically before nowcasting, Rt
+ and alert calculation, and identify missing/excess parameter pairs in errors.
+ Reject mixed-disease results at the legacy conversion boundary.
+
+- Test deprecation on both sides of the 1.3.0 boundary and align the migration
+ guide with the approved support policy.
+
+- Add mandatory real-INLA integration, controlled host/container benchmarking,
+ and explicit propagation of fit failures and terminated municipal workers.
+ Interrupted parallel work cannot be returned as a complete pipeline result.
+
+- Exercise the pinned consumer's state/municipality recovery and RData/SQL
+ publication against disposable databases. Retain parameter metadata through
+ municipal concatenation and preserve numeric precision in SQL exports.
+
- Compare candidate results against the consumer's pinned e460b3b8 calculation
and history functions with immutable reference snapshots. Preserve the
historical ID format for legacy alert objects; modern result IDs are unchanged.
@@ -25,8 +40,8 @@
- Began package metadata, dependency, documentation, and CI cleanup.
- Isolated all SQL behind an internal DBI repository with centralized physical
table mappings, bound values, quoted identifiers, and stable domain schemas.
-- Removed fallback to a global `con`; database-backed public functions now
- require an explicit `datasource` connection.
+- Require explicit connections in the modern database API; preserve the legacy
+ pipeline's `datasource = con` default during the approved transition.
- Replaced row-at-a-time writes with transactional staging-table operations and
explicit `error`, `update`, and `ignore` conflict policies.
- Added integration coverage for cases, individual records, climate,
diff --git a/R/alert_functions.R b/R/alert_functions.R
index b6eb2ff..6e0f382 100644
--- a/R/alert_functions.R
+++ b/R/alert_functions.R
@@ -396,7 +396,6 @@ pipe_infodengue <- function(cities, cid10="A90", datarelatorio, finalday = NULL,
legacy
}
-
.legacy_alert_parameters <- function(obj) {
parameters <- attr(obj, "parameters")
if (is.null(parameters)) {
@@ -795,14 +794,13 @@ tabela_historico_intra <- function(obj, iniSE, lastSE, versao,
driver, DBI::Id(schema = config[[1]], table = config[[2]])
))
column_sql <- as.character(DBI::dbQuoteIdentifier(driver, names(dados)))
- row_sql <- apply(dados, 1L, function(row) {
- values <- Map(function(value, template) {
+ row_sql <- vapply(seq_len(nrow(dados)), function(index) {
+ values <- lapply(dados[index, , drop = FALSE], function(value) {
if (is.na(value)) return(DBI::SQL("NULL"))
- if (inherits(template, "Date")) value <- as.Date(value)
DBI::dbQuoteLiteral(driver, value)
- }, as.list(row), dados[1, , drop = FALSE])
+ })
paste0("(", paste(as.character(values), collapse = ", "), ")")
- })
+ }, character(1))
sql <- paste("INSERT INTO", table_sql,
paste0("(", paste(column_sql, collapse = ", "), ") VALUES"),
paste(row_sql, collapse = ", "))
diff --git a/docs/refactoring/concurrency.md b/docs/refactoring/concurrency.md
index c15d134..0ef353d 100644
--- a/docs/refactoring/concurrency.md
+++ b/docs/refactoring/concurrency.md
@@ -59,14 +59,56 @@ insuficientes para definir limites operacionais. Os defaults permanecem 1/1.
O CSV registra o SHA-256 dos fontes R usados; a carga sintética e o supervisor
estão versionados com esta entrega.
-## Validação real do motor
-
-O runner `Rscript tools/run-inla-integration.R /tmp/inla-evidence` exige dois
-cenários: equivalência serial/paralela e repetição com INLA real, além da
-rejeição de saída parcial quando um worker é encerrado. Nenhum pode ser ignorado.
-O benchmark `tools/benchmark-inla.py` mede processos externos, municipais e
-threads com orçamento explícito e preserva as diferenças entre orçamentos.
-A imagem `tools/inla-validation.Dockerfile` fixa a base e o runtime oficial
-INLA 25.12.16 para Linux ARM, incluindo a dependência de amostragem `sn`.
-Comparação com a referência histórica e recuperação integrada do consumidor
-são acrescentadas nas etapas seguintes da cadeia. Os defaults continuam 1/1.
+## Validação com INLA real após o review de 29/10/2026
+
+O runner dedicado executa quatro cenários obrigatórios:
+
+```sh
+Rscript tools/run-inla-integration.R /tmp/inla-evidence
+```
+
+Ele falha se INLA estiver ausente, se algum cenário for ignorado ou se a chamada
+bayesiana apenas devolver os casos brutos. Os cenários cobrem repetição,
+concorrência municipal com uma e duas threads de ajuste, referência histórica,
+fallback real do consumidor com falhas injetadas e encerramento de um worker.
+Falha de ajuste preserva seu diagnóstico; a camada paralela rejeita saída parcial.
+O caso de encerramento mata um worker controlado, não força OOM no computador.
+
+As entradas são sintéticas: 60 semanas, atrasos de zero a quatro semanas,
+dois municípios e dengue/chikungunya. O comparador exige tolerância absoluta
+`1e-7`, igualdade de categorias e de ausência de dados. A referência mantém os
+corpos históricos imutáveis e adapta somente as dependências externas para o
+mesmo ambiente e a semente explícita de amostragem. A comparação com a referência
+usa quatro threads de ajuste, como o código antigo. Não valida a instalação
+integral da imagem operacional antiga.
+
+Alterar as threads do ajuste não é pressuposto numericamente idêntico. O
+benchmark conserva baselines por orçamento de threads, compara concorrência e
+repetições contra esses baselines e exporta separadamente diferenças entre
+orçamentos. Mudanças de nível de alerta entre orçamentos falham a execução;
+outras diferenças permanecem visíveis para avaliação científica.
+
+```sh
+python3 tools/benchmark-inla.py /tmp/inla-host --environment host --max-rss-mib 3072
+docker build -f tools/inla-validation.Dockerfile -t alerttools-inla-validation .
+```
+
+A matriz mede uma ou duas cópias externas da carga, um ou dois processos
+municipais e uma ou duas threads de ajuste, com três repetições. As cópias
+representam a disputa de recursos entre estados; não são uma execução nacional.
+Cada rodada registra tempo de parede incluindo startup, tempo de cálculo nos
+workers, versões, entrada, semente e RSS agregado amostrado a cada 100 ms.
+O supervisor encerra os grupos de processos ao exceder tempo/memória ou falhar.
+O RSS pode contar páginas compartilhadas várias vezes. Em contêiner, as métricas
+de cgroup têm escopo da vida inteira do contêiner e são identificadas dessa forma.
+
+A imagem de teste fixa a base por digest e o INLA R/motor em 25.12.16, build
+oficial disponível no repositório testing. Isso identifica um ambiente de teste,
+não uma recomendação de versão para produção. Os builds ARM 26.08.07/26.08.22
+encontrados apresentaram incompatibilidade de biblioteca/instrução na máquina
+local. O instalador do build anterior requer carregar INLA; o launcher ARM
+precisa de um alias do nome `inla.mkl` para o executável oficial `inla`.
+Nenhum cálculo do motor é modificado. O build testa um ajuste real antes de aceitar a imagem.
+
+Os defaults continuam 1/1. Uma medição sintética e uma imagem de teste não
+substituem dimensionamento com a carga operacional e revisão científica.
diff --git a/docs/refactoring/consumer-integration.md b/docs/refactoring/consumer-integration.md
new file mode 100644
index 0000000..ac9af8d
--- /dev/null
+++ b/docs/refactoring/consumer-integration.md
@@ -0,0 +1,80 @@
+# Recorte integrado do consumidor
+
+Os cenários bayesianos reais de recuperação acrescentados após o review de
+29/10/2026 são executados pelo runner `tools/run-inla-integration.R`, descrito
+em `concurrency.md`. Eles complementam o recorte DBI/SQL abaixo, que permanece
+no modo `none`; não equivalem à execução integral da imagem operacional.
+
+O teste executa expressões sem alterações de `main/main_BR.R` na revisão
+`27a03f26a9bf366597ef135e7da8d2f620ea9a8e` do AlertaDengueAnalise. O pin do
+AlertTools continua sendo `e460b3b8c15ab28e8755f482d576cf7280803b34`. O manifesto
+em `tests/reference/consumer-27a03f26` registra o blob original e os hashes das
+funções e dos três blocos reais de exportação SQL selecionados.
+
+`tools/prepare-consumer-reference.R` extrai as expressões do fonte original,
+verifica seu blob e confirma igualdade das expressões R. Não executa o startup
+do consumidor, sua configuração global, SSH/SCP ou um banco operacional.
+
+## O que é executado
+
+- `run_disease_pipeline()`, `run_disease_pipeline_by_city()`,
+ `run_city_pipeline()` e `combine_ale_parts()` reais;
+- processamento estadual de dois municípios, falha estadual injetada com
+ recuperação completa, isolamento de um município com falha e falha de todos;
+- dengue, chikungunya e Zika com fallback legado;
+- `load_state_result()` e `normalize_ale()` reais para verificar o objeto `res`
+ em `.RData`, sua estrutura e conteúdo, sem exigir identidade binária;
+- os três blocos reais de exportação SQL por doença;
+- persistência DBI idempotente; no PostgreSQL, replay dos SQLs produzidos pelo
+ escritor da referência e pelo escritor candidato, comparando todas as colunas.
+
+As entradas são sintéticas, usam as consultas reais da candidata e um banco
+descartável. As funções de cálculo, conversão e SQL da referência são as do pin
+antigo; sua leitura é adaptada à mesma entrada DBI controlada. Esse adaptador não
+valida o SQL de leitura antigo ou a instalação integral da imagem operacional.
+O modo é `none`, sem inferência de equivalência bayesiana. A precisão numérica é
+comparada com tolerância absoluta `1e-7`; há um teste específico de exportação
+com `1e-12` para detectar coerção/formatação acidental de probabilidades.
+As tabelas são alinhadas pelas chaves municipais, doença, semana e localidade
+antes da comparação: a API nova ordena municípios, enquanto o consumidor antigo
+pode preservar a ordem de consulta. Chaves duplicadas ou incompletas falham.
+
+## Correções de compatibilidade encontradas
+
+A recuperação municipal concatena listas com `c()`, perdendo o atributo externo
+de parâmetros. Cada objeto `alerta` agora carrega os próprios parâmetros como
+atributo, sem alterar seus campos públicos. O conversor recupera esses valores
+dos filhos e continua rejeitando dados incompletos ou conflitantes.
+
+A geração SQL preserva os tipos de cada célula ao cotar literais, em vez de
+converter uma linha inteira em matriz de caracteres. Isso evita formatação
+numérica dependente da coerção. A persistência continua com conexão explícita;
+nenhum efeito de escrita foi introduzido no cálculo.
+
+## CI e evidências
+
+O job existente de PostgreSQL usa PostgreSQL 16 efêmero e executa
+`tools/run-postgres-integration.R`. O runner exige `ALERTTOOLS_TEST_POSTGRES=true`,
+o banco dedicado `alerttools_test` e RPostgres instalado; falha se o cenário
+PostgreSQL do consumidor for ignorado. Upload preserva CSVs de comparação,
+RData/SQLs de ambas as versões, resultados da suíte, ambiente e manifests,
+inclusive em uma falha de verificação.
+
+```sh
+ALERTTOOLS_TEST_POSTGRES=true PGDATABASE=alerttools_test \
+ Rscript tools/run-postgres-integration.R consumer-evidence
+```
+
+O helper de integração recria schemas somente no banco dedicado de teste.
+Para uma validação local sem PostgreSQL, o teste SQLite exercita os mesmos
+contratos, artefatos e persistência, mas não substitui o replay PostgreSQL da CI.
+
+## Limites de aprovação
+
+Isto é um recorte representativo do consumidor com origem verificável, não uma
+execução nacional do `main_BR.R`. Permanecem pendentes infraestrutura e dados
+operacionais anonimizados, avaliação bayesiana, publicação/implantação externa,
+responsáveis e aprovação científica. O registro de consumidores não é marcado
+como migrado ou validado em produção por causa destes testes. A troca da
+dependência no repositório consumidor continua sendo um PR separado, após
+essas evidências e seu plano de rollback.
diff --git a/docs/refactoring/correcoes-review-2026-10-29.md b/docs/refactoring/correcoes-review-2026-10-29.md
new file mode 100644
index 0000000..683601b
--- /dev/null
+++ b/docs/refactoring/correcoes-review-2026-10-29.md
@@ -0,0 +1,151 @@
+# Correções dos reviews: implementação e validação local
+
+Data: 29/10/2026. Candidata consolidada: `codex/review-corrections-2026-10-29`.
+
+As correções de código foram implementadas, testadas e organizadas em nove
+branches locais `codex/review-ready/*`. Nenhuma branch foi enviada ao GitHub,
+nenhum PR foi mesclado e nenhuma release ou migração foi executada.
+O estado público dos PRs ainda não contém estas alterações.
+
+## Atendimento dos comentários
+
+| Destino | Correção local | Evidência principal |
+|---|---|---|
+| #28 | Preservar parâmetros em cada alerta municipal e recuperá-los após `do.call(c, ...)`; rejeitar parâmetros ausentes/conflitantes sem consultar o banco | `test-legacy-fallback.R`; helper validado antes do join, sem depender do #32/#37 |
+| #30 | Isolar a leitura da versão; testar 1.2.0/1.2.9 sem aviso e 1.3.0/1.4.0 com aviso real de `lifecycle`; documentar a política aprovada | `test-deprecation-policy.R`, `api-migration.md` |
+| #31 | Antecipar do #32 o processamento completo por município/doença, inclusive histórico e validações dos pares; apontar pares ausentes/excedentes nos erros | `test-pipeline-group-keys.R`, `test-core-pipeline.R` |
+| #31 | Corrigir regressão encontrada na validação: entradas em ordem inversa alteravam Rt e alertas; ordenar semanas antes do cálculo | `test-pipeline-group-order.R`: execução conjunta/reordenada versus execuções isoladas |
+| #32 | Rejeitar múltiplos CID10 ou divergência entre dados e parâmetros antes da conversão para objetos legados | `test-legacy-disease-guard.R`; API moderna continua aceitando múltiplas doenças |
+| #33 | Validar CSV e preservar procedência da auditoria somente leitura, sem sobrescrever relatórios | CLI exercitada no PostgreSQL descartável; homologação continua pendente |
+| #34 | INLA real serial/paralelo, repetição e worker encerrado; preservar diagnóstico do ajuste e impedir retorno parcial como completo | Dois cenários próprios obrigatórios, seis verificações no snapshot independente do #34 |
+| #34 | Benchmark com concorrência externa/municipal/threads, tempo e memória no host e em Docker | 48 rodadas; relatório em `benchmarks/inla-2026-10-29.md` |
+| #35 | Preservar o contrato aprovado de `minimum_history`/`dy`, sem habilitar regra epidemiológica | ASTs dos 15 fontes R idênticas às do #34; alteração documental |
+| #36 | Acrescentar comparação bayesiana real com os corpos históricos imutáveis e o orçamento antigo de quatro threads | Cenário próprio de referência; runner exige três cenários nessa etapa |
+| #37 | Acrescentar fallback bayesiano real do consumidor, isolamento de falha e artefatos; preservar precisão SQL e replay PostgreSQL existentes | Runner final exige quatro cenários; referências e recuperação não são dependências antecipadas do #34 |
+
+## Validação concluída
+
+| Verificação | Resultado |
+|---|---|
+| Suíte completa com PostgreSQL 16 descartável | 474 verificações aprovadas, zero falhas/warnings; quatro cenários INLA reservados ao runner dedicado |
+| INLA real no macOS ARM | Quatro cenários obrigatórios, 14 verificações, zero falhas/warnings/skips |
+| INLA real no Linux ARM/Docker | Quatro cenários obrigatórios, 14 verificações, zero falhas/warnings/skips |
+| #34 isolado dos PRs posteriores | Dois cenários obrigatórios de INLA real e seis verificações aprovadas |
+| #36 isolado do consumidor do #37 | Três cenários obrigatórios de INLA real e sete verificações aprovadas |
+| Pontos intermediários #28/#30/#31/#32/#33/#34/#36 | Testes pertinentes aprovados, com warnings tratados como falha no verificador local |
+| Lint | Aprovado em Docker |
+| R CMD check em Docker | Zero erros, zero warnings, uma nota sobre o `con` global legado |
+| Auditoria CLI | Somente leitura, metadados, bloqueio de sobrescrita e de municípios duplicados aprovados no banco descartável |
+
+O check construiu as vignettes, usou `--no-manual`, desativou a exigência de
+todos os Suggests e a verificação do relógio. A nota de `con` corresponde ao
+default legado preservado por solicitação de compatibilidade; não foi ocultada.
+Os testes bayesianos obrigatórios foram executados separadamente, sem skips.
+A normalização final de linhas vazias em dez arquivos de validação foi conferida
+por AST: nenhuma expressão R mudou; as diferenças estão registradas nas evidências.
+Mensagens nativas de NUMA/`mbind` do contêiner permanecem nos logs; nenhuma
+permissão privilegiada foi acrescentada para suprimi-las.
+
+As evidências estão em [evidence/review-2026-10-29](evidence/review-2026-10-29).
+Os CSVs registram testes, fontes, ambientes, repetições e comparações. RDS/RData/SQL
+contêm apenas a carga sintética utilizada nesta validação.
+
+## Resultado do benchmark
+
+Houve 2.088 comparações coincidentes por ambiente, mantendo fixo o orçamento
+de threads. Ao mudar esse orçamento, diferenças nos limites dos intervalos
+posteriores continuaram marcadas como `mismatch`: até uma unidade no inferior
+e até 0,025 no superior. Casos medianos, Rt e alertas coincidiram nesse recorte.
+As tolerâncias não foram ampliadas para aprovar esses limites diferentes.
+
+No Docker de duas CPUs, acrescentar paralelismo municipal a duas cópias externas
+aumentou tempo e RSS. Os defaults permanecem 1/1. RSS agregado pode contar
+memória compartilhada várias vezes; a interrupção pelo orçamento de 2 GiB não
+foi OOM do computador. A matriz completa foi concluída com orçamento explícito
+de 3 GiB. Consultar [o relatório de recursos](benchmarks/inla-2026-10-29.md).
+
+Os ambientes têm versões distintas: macOS R 4.4.3/INLA 24.12.11 e Linux
+R 4.6.1/INLA 25.12.16. O build oficial 25.12.16 do repositório testing foi
+fixado para o ambiente ARM de teste; isso não recomenda uma versão para produção.
+A comparação histórica usa o mesmo motor nos dois lados e explicita a adaptação
+de sementes/dependências externas. Não é uma execução da imagem nacional antiga.
+
+## Cadeia local e preservação do histórico
+
+```text
+master ← #20 ← #28 ← #30 ← #31 ← #32 ← #33 ← #34 ← #35 ← #36 ← #37
+```
+
+- #27 e #29 continuam mesclados e seus commits de merge foram preservados como
+ ancestrais do #28 preparado. A base atual foi incorporada sem perder o #29.
+- O problema de parâmetros já corrigido no #37 foi antecipado para o #28.
+- O processamento por município/doença do antigo #32 foi antecipado para o #31;
+ o novo diff do #32 se concentra na proteção do adaptador legado.
+- O comparador comum e o teste de concorrência chegam no #34. A referência
+ histórica chega no #36 e o cenário do consumidor no #37. O runner exige
+ respectivamente dois, três e quatro cenários, sem aprovação por ausência de testes.
+- A implementação duplicada do helper de parâmetros foi removida na reaplicação
+ do #37. Fontes, testes e workflows da ponta local correspondem à candidata consolidada.
+- Foram criadas referências de segurança antes da reconstrução. Nenhuma ref
+ remota mudou durante o trabalho. Os PRs #27/#29 não foram reabertos.
+
+O [manifesto das branches](evidence/review-2026-10-29/ready-refs.json) registra
+as refs de preparação e as heads remotas observadas. SHAs de validação podem
+anteceder commits somente de evidências/documentação. Antes de publicar,
+resolver novamente a ponta de cada branch e conferir o remoto.
+
+## Pendências e próxima etapa
+
+1. **Auditoria Zika em homologação:** o repositório não fornece configuração de
+ acesso nem a lista operacional de municípios. Não substituir por fixtures,
+ credenciais da CI ou municípios deduzidos. A ferramenta está pronta e testada;
+ a execução real depende desses dois insumos.
+2. **Avaliação científica/operacional:** avaliar os intervalos posteriores ao
+ mudar threads e dimensionar a carga nacional antes de migrar o consumidor.
+ Não alterar seu registro para migrado ou validado em produção.
+3. **Publicação, conforme a próxima instrução do usuário:** atualizar refs,
+ reconciliar qualquer alteração externa e enviar as branches preparadas para
+ as branches originais dos PRs, de pais para filhos, com lease no SHA observado.
+ Não fazer push irrestrito nem merge automático.
+4. **CI/revisão depois do envio:** conferir os novos checks no SHA publicado e
+ solicitar nova revisão quando autorizado. Os checks antigos e aprovações
+ anteriores não certificam as novas heads.
+
+## Respostas preparadas para os reviews
+
+Textos para usar depois da publicação; não foram postados.
+
+**#28:** A correção foi antecipada do #37. Cada alerta municipal preserva seus
+parâmetros e o histórico os recupera após a concatenação real do fallback, sem
+consulta implícita ao banco. O teste cobre parâmetros diferentes por município,
+ausência e conflito. O merge do #29 foi preservado na atualização da base.
+
+**#30:** A leitura da versão foi isolada e os testes agora exercitam ausência de
+aviso em 1.2.x e emissão real de `lifecycle` desde 1.3.0. O guia reflete a política
+aprovada. A branch foi reaplicada sobre a base que já contém o #29.
+
+**#31:** O cálculo, as validações e o histórico usam município/doença de forma
+coerente. A implementação que estava no #32 foi antecipada para este PR. Os
+erros identificam pares ausentes/excedentes; testes verificam doenças distintas
+e entradas reordenadas. Foi corrigida também a ordenação semanal antes de Rt/alertas.
+
+**#32:** O conversor legado rejeita explicitamente múltiplos CID10 e inconsistência
+entre dados e parâmetros. A API moderna preserva o processamento de várias
+doenças. O diff foi reduzido ao escopo restante após a antecipação do cálculo para o #31.
+
+**#33:** A auditoria ganhou validação de entrada e evidências de procedência,
+com teste somente leitura em PostgreSQL descartável. A política legada foi
+preservada. A auditoria de homologação ainda depende de acesso e da lista
+operacional de municípios, que não foram encontrados no repositório.
+
+**#34:** Foram acrescentados testes com INLA real e um job obrigatório, sem skips.
+Há medições de concorrência externa/municipal/threads no host e em Docker,
+incluindo tempo, memória, repetição e interrupção controlada. Os resultados por
+orçamento, diferenças entre threads e a interrupção por orçamento de RSS estão
+preservados no relatório; os defaults continuam conservadores.
+
+**#35–37:** Os contratos aprovados foram preservados na cadeia local. O #36
+acrescenta a comparação bayesiana real e o #37 a recuperação bayesiana do
+consumidor. Precisão SQL, comparação não bayesiana, snapshots imutáveis e replay
+PostgreSQL continuam cobertos. A aprovação de migração operacional permanece
+condicionada às evidências de homologação e avaliação científica.
diff --git a/docs/refactoring/evidence/review-2026-10-29/R-CMD-check.txt b/docs/refactoring/evidence/review-2026-10-29/R-CMD-check.txt
new file mode 100644
index 0000000..5222f7a
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/R-CMD-check.txt
@@ -0,0 +1,98 @@
+── R CMD build ─────────────────────────────────────────────────────────────────
+* checking for file ‘.../DESCRIPTION’ ... OK
+* preparing ‘AlertTools’:
+* checking DESCRIPTION meta-information ... OK
+* installing the package (it is needed to build vignettes)
+* creating vignettes ... OK
+* checking for LF line-endings in source and make files and shell scripts
+* checking for empty or unneeded directories
+Removed empty directory ‘AlertTools/tests/testthat/_snaps’
+* building ‘AlertTools_1.2.0.tar.gz’
+
+── R CMD check ─────────────────────────────────────────────────────────────────
+* using log directory ‘/evidence/alerttools-review-Rcheck-consolidated/AlertTools.Rcheck’
+* using R version 4.6.1 (2026-06-24)
+* using platform: aarch64-unknown-linux-gnu
+* R was compiled by
+ aarch64-linux-gnu-gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
+ GNU Fortran (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
+* running under: Ubuntu 24.04.4 LTS
+* using session charset: UTF-8
+* current time: 2026-10-29 16:53:30 UTC
+* using option ‘--no-manual’
+* checking for file ‘AlertTools/DESCRIPTION’ ... OK
+* checking extension type ... Package
+* this is package ‘AlertTools’ version ‘1.2.0’
+* package encoding: UTF-8
+* checking package namespace information ... OK
+* checking package dependencies ... INFO
+Packages suggested but not available for checking:
+ 'brpop', 'covr', 'data.table', 'mem', 'styler'
+* checking if this is a source package ... OK
+* checking if there is a namespace ... OK
+* checking for .dll and .exe files ... OK
+* checking for hidden files and directories ... OK
+* checking for portable file names ... OK
+* checking for sufficient/correct file permissions ... OK
+* checking whether package ‘AlertTools’ can be installed ... OK
+* checking installed package size ... OK
+* checking package directory ... OK
+* checking ‘build’ directory ... OK
+* checking DESCRIPTION meta-information ... OK
+* checking top-level files ... OK
+* checking for left-over files ... OK
+* checking index information ... OK
+* checking package subdirectories ... OK
+* checking code files for non-ASCII characters ... OK
+* checking R files for syntax errors ... OK
+* checking whether the package can be loaded ... OK
+* checking whether the package can be loaded with stated dependencies ... OK
+* checking whether the package can be unloaded cleanly ... OK
+* checking whether the namespace can be loaded with stated dependencies ... OK
+* checking whether the namespace can be unloaded cleanly ... OK
+* checking loading without being on the library search path ... OK
+* checking dependencies in R code ... OK
+* checking S3 generic/method consistency ... OK
+* checking replacement functions ... OK
+* checking foreign function calls ... OK
+* checking R code for possible problems ... NOTE
+pipe_infodengue: no visible binding for global variable ‘con’
+Undefined global functions or variables:
+ con
+* checking Rd files ... OK
+* checking Rd metadata ... OK
+* checking Rd cross-references ... OK
+* checking for missing documentation entries ... OK
+* checking for code/documentation mismatches ... OK
+* checking Rd \usage sections ... OK
+* checking Rd contents ... OK
+* checking for unstated dependencies in examples ... OK
+* checking contents of ‘data’ directory ... OK
+* checking data for non-ASCII characters ... OK
+* checking LazyData ... OK
+* checking data for ASCII and uncompressed saves ... OK
+* checking R/sysdata.rda ... OK
+* checking installed files from ‘inst/doc’ ... OK
+* checking files in ‘vignettes’ ... OK
+* checking examples ... OK
+* checking for unstated dependencies in ‘tests’ ... OK
+* checking tests ...
+ Running ‘testthat.R’
+ OK
+* checking for unstated dependencies in vignettes ... OK
+* checking package vignettes ... OK
+* checking re-building of vignette outputs ... OK
+* DONE
+Status: 1 NOTE
+See
+ ‘/evidence/alerttools-review-Rcheck-consolidated/AlertTools.Rcheck/00check.log’
+for details.
+── R CMD check results ─────────────────────────────────── AlertTools 1.2.0 ────
+Duration: 38.4s
+
+❯ checking R code for possible problems ... NOTE
+ pipe_infodengue: no visible binding for global variable ‘con’
+ Undefined global functions or variables:
+ con
+
+0 errors ✔ | 0 warnings ✔ | 1 note ✖
diff --git a/docs/refactoring/evidence/review-2026-10-29/audit-cli-verification.txt b/docs/refactoring/evidence/review-2026-10-29/audit-cli-verification.txt
new file mode 100644
index 0000000..341a6f5
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/audit-cli-verification.txt
@@ -0,0 +1 @@
+Audit command validated only against disposable PostgreSQL 16 alerttools_test. Read-only report, input provenance, output overwrite guard and duplicate-input guard passed. No operational or staging database was audited.
diff --git a/docs/refactoring/evidence/review-2026-10-29/evidence-sha256.csv b/docs/refactoring/evidence/review-2026-10-29/evidence-sha256.csv
new file mode 100644
index 0000000..ca12b5f
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/evidence-sha256.csv
@@ -0,0 +1,73 @@
+file,sha256
+R-CMD-check.txt,625c90bc5bb3cc9a0dcf3f2eac556adb77e9d2d67e515dba3d69a060479ef011
+audit-cli-verification.txt,bc5d462918530fc77adec54a52dbd8ce84c1c993d81b4501d41cffb71cb356ec
+benchmarks/budget-2048-failure.txt,dd52eda13d249f4fb762cf5ecf27a2c1ed8b0c2b53892bf583918c65d1728cac
+benchmarks/budget-2048-protocol.json,debb640cf66617ab824b527a17827a9a8c3e38f8f85199e472b53884801dc592
+benchmarks/calculation-source-blobs.csv,b41e215eaa48a84a045504d0cd6ee15f2088cd40b1238a0129bfba2888765339
+benchmarks/docker/container-lifetime-cpu.max.txt,07eb5019b2babb019fbbfe1cb328ec5b7affac5e07da4b94ebedb5e110dfab69
+benchmarks/docker/container-lifetime-memory.events.txt,28fe05a1d7b8467a03fb54454f7b6a130fab752864d0454f5f6c4a4b6ce307f2
+benchmarks/docker/container-lifetime-memory.max.txt,e299e7e064963e64b8955bf05efe3e8151603ac8410068ae44c09285dd88707b
+benchmarks/docker/container-lifetime-memory.peak.txt,183239cefffb2bf24caafc30b55d08a415cca1780b6c59b911ec4deda64e473b
+benchmarks/docker/cross-thread-comparison.csv,a8c0e0c3549f9f9c23db5ba2fbe38d114c04497c96387f446143836d8f1e2783
+benchmarks/docker/image.json,48d307a59b66645015ab53b3eed6d3c0909f0b1e0bb6e1bfff4056c609e3bab1
+benchmarks/docker/protocol.json,740d46cff7025194c7b395f6e02dc1ffb06577407189a8aa42744c647e68849a
+benchmarks/docker/runs.csv,e84f760bac30d80fa2ef4320ba48fee8d4cc34d9267ac1f791d88a3d3aef42d1
+benchmarks/docker/runtime.csv,406d493b56f121a9feaf1a072e667735082bcb93c41f2b56c4a593a1d17c9b42
+benchmarks/docker/within-budget-comparison.csv,1bb626cc69b9e62270a77426238b24d9a7b775f4e19855155b3416913bd9e5a9
+benchmarks/host/cross-thread-comparison.csv,bf079437df69fcb35364e828f0bcf5160fb8e43f0b88a90c3fa942a3d13a26bb
+benchmarks/host/protocol.json,c57c8be80228388142e8317953ec10d09e0c8923e777cb463fe8a762b28d9b10
+benchmarks/host/runs.csv,3b39ac6d9f7e579f68ff87ec0cb9a14b90361d3f421c7ccc280e9e8669a0840f
+benchmarks/host/runtime.csv,95c91b2bfdd6fc06b4f9bfa75d5a90b54bb35502f99941941649a4ba604b5f97
+benchmarks/host/within-budget-comparison.csv,1bb626cc69b9e62270a77426238b24d9a7b775f4e19855155b3416913bd9e5a9
+benchmarks/source-snapshot.tar.gz,3941ed4f367d08596bd46a52a497898cc93eb3abc21a9d7d6e52b90855f2cbbd
+benchmarks/source.json,64126783c071de9cbe4ec1bfa56d73bed82acfac0d5fef660bb5091b86bd2215
+benchmarks/summary.csv,a6830c134c24403aca07ef6b3d67fd942e7399fcfc24f3e8081ea8e2f6082b54
+initial-refs.json,c8391b48a1eee1f3375182179892d97e065a5268799a89007c39bc12f10d6770
+inla/docker/candidate-sources.csv,acbc67e267a8021c07d62479cd322a1c585467f2331a8ebc3bd684d6fedf3560
+inla/docker/environment.txt,3f33f493aacaea16ff7d614c496e18526e772b16c3400c6f0de4a50899910fbc
+inla/docker/parallel-threads-1.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+inla/docker/parallel-threads-1.rds,9d60500d6da511c96af6048ddcf89e41992f50977c20b58aadf9814cf2148168
+inla/docker/parallel-threads-2.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+inla/docker/parallel-threads-2.rds,ed4d465c88dd1c56446df2bb9b28ed1fceab610112feb7e508e51de6a654ff1c
+inla/docker/reference-comparison.csv,e0342c7d9d02a75ad26dcc28293392e16267cec5fcf47e980be1fc61b4a6ab35
+inla/docker/reference-comparison.rds,5397b7b2eaf57d81c50d0b3660cbf03e290dfe4d661bb1617f496cd23c3dc192
+inla/docker/state.RData,bea8de414a19d0aed44f90127ee7aa1931d124650b6875cb147195246cfe09dd
+inla/docker/state.sql,7ceb136732f8e9ee0e5086fcec40bf9234e601f7e7d50609ca881aa7c8a6d9e0
+inla/docker/test-results.csv,27aae840a23b35d4a5b04a8e818932c9348247b62b35901504a00e4e0688c616
+inla/host/candidate-sources.csv,acbc67e267a8021c07d62479cd322a1c585467f2331a8ebc3bd684d6fedf3560
+inla/host/environment.txt,2577ecfc5fb1359c706bd1b78f667454f7a740b92154fc75e8542fcb3b7efbc2
+inla/host/parallel-threads-1.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+inla/host/parallel-threads-1.rds,23493af170394628555f193e93b0fb4d04ce151d7a9b285a77511b294c8f3d72
+inla/host/parallel-threads-2.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+inla/host/parallel-threads-2.rds,feffc89dbe9c4ff163ef50df790ec8031554034ebdf7c302e588eeb9192bfc4b
+inla/host/reference-comparison.csv,e0342c7d9d02a75ad26dcc28293392e16267cec5fcf47e980be1fc61b4a6ab35
+inla/host/reference-comparison.rds,906c01c5416479d736103bcfc02a2c3c724d5cec12ca42430b3fe26bd75bb3d7
+inla/host/state.RData,603c2e68155efda10c6cf575bda38f5c4963b3fa372cd657d1d6f9abe755c183
+inla/host/state.sql,6863c47e1482dcdce10e6470c35a89c1241217b4b0d2aac4f4c75e15b6737834
+inla/host/test-results.csv,da87d0057bc099f30171f492d404e678a1c1d67488040ba7917601a063040e53
+lint.txt,1d670927d1333b233cea04397076e6a9d4a87f4983ebc7a0ba98796798d9acf1
+local-pr-checks/alerttools-review-local-pr28-final.csv,7fe1324134d9d38d0af4784bc66ac25f27aee19843f6d5745261090cfc258593
+local-pr-checks/alerttools-review-local-pr30-final.csv,2bbbf9f287791dfda7d180d7bc189a74ee5d25e988cf77830ebe7adb4e99ca62
+local-pr-checks/alerttools-review-local-pr31-final.csv,30630ce7569dbd26f2d0bfaed7900811c33ff5bdcd739c15fb10bf4d1b751cc8
+local-pr-checks/alerttools-review-local-pr32-final.csv,67ef480ee95be41109de81d0f96157d84e52eb54bedf4824132d712c95906b64
+local-pr-checks/alerttools-review-local-pr33-final.csv,cf4ca2e8264018e091615c00ecc847d530dbe919d3bb65a5367f9d5e0a67543d
+local-pr-checks/alerttools-review-local-pr34-final.csv,629680b1476cf87aba75d19e234c85139256d6023fa7c533e4aed1fc13cf268b
+local-pr-checks/alerttools-review-local-pr36-final.csv,66e96d0d99f1693abd5fe81027411def610cc8668f0efc736093ffb89a869f56
+local-pr-checks.json,b473b7191a52797b183837794611247765f08862880184c0f8154ea7b84f90c3
+local-pr34-inla/candidate-sources.csv,23bcf667e5f59d84c1921da5cc0f702f98cb8f198ae510f7b44e4577296af452
+local-pr34-inla/environment.txt,3f33f493aacaea16ff7d614c496e18526e772b16c3400c6f0de4a50899910fbc
+local-pr34-inla/parallel-threads-1.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+local-pr34-inla/parallel-threads-2.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+local-pr34-inla/test-results.csv,7e3caa2164c647e0d66cdbff4870a6a483821c81ca8d757feeec206092c22ace
+local-pr36-inla/candidate-sources.csv,1e74342c202f24ea9ba5c8d61ce3b1703359bf76910c79be9c97b85ed8c4fb97
+local-pr36-inla/environment.txt,3f33f493aacaea16ff7d614c496e18526e772b16c3400c6f0de4a50899910fbc
+local-pr36-inla/parallel-threads-1.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+local-pr36-inla/parallel-threads-2.csv,4060c36b24742c47410004681b32c8ef5809e95e6999e68e8a2ace2fe79727e5
+local-pr36-inla/reference-comparison.csv,e0342c7d9d02a75ad26dcc28293392e16267cec5fcf47e980be1fc61b4a6ab35
+local-pr36-inla/test-results.csv,a9983b24c02f29c56ed6c2a3f5b89222019bdb205fa5d50b8ebf9715d78c95e0
+postgres/candidate-sources.csv,68d0d2da4b6950411a0beea9b0508588ed449f9959a92baa8346523682201d0d
+postgres/environment.txt,e623b06fc897231f4e753f1153a38e441cf0afba9b7e399d04e5ece727155c9f
+postgres/test-results.csv,48bd3f1b6766f02d7acf457909fc2c487d178472e9943228fe513e6da40ed99c
+pr35-ast-check.txt,61c5451b61d38dea109f6a83380eb244adc719362d17088d85805c12fb090ef7
+ready-refs.json,3d37fc31b55b880f84be3499b8aa476f3be26fa60d28a5e386cc3adf630308bb
+validation-eof-ast-proof.json,1dc934188f26afbc23bed274d5c0afd3883c7d8a572ff5e89d52b5a51fe7ee2e
diff --git a/docs/refactoring/evidence/review-2026-10-29/initial-refs.json b/docs/refactoring/evidence/review-2026-10-29/initial-refs.json
new file mode 100644
index 0000000..64ed1f8
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/initial-refs.json
@@ -0,0 +1,13 @@
+{
+ "master": "e460b3b8c15ab28e8755f482d576cf7280803b34",
+ "codex/alerttools-1.2.0-rc1": "57428ed998032a5d958afeb55a372145cd0b8601",
+ "codex/pr2-legacy-compat": "7213aa10fc9d8c2c2830406b183f4e4c99c55d10",
+ "codex/pr4-deprecation-policy": "0fd9c0da8f3d830d115f7034102f74038f63aefb",
+ "codex/pr5-canonical-inputs": "c6fe5ccd7b7cb87aa8c114e97e57984655eb9bff",
+ "codex/pr6-municipality-disease": "3d62c689633af001ddb97884213b081f862a4768",
+ "codex/pr7-zika-transition": "88efaf004725d1bd031117f59edb5595f629d6a5",
+ "codex/pr8-concurrency-controls": "e7de3e71b7e95e2c79cf6391565a4b760536ea63",
+ "codex/pr9-minimum-history-contract": "2f5ad3e327d36aaea357318875051e2449a469c1",
+ "codex/pr10-epidemiological-equivalence": "1534d94ee7ff0d80fb8562eb46b6b1754f927f22",
+ "codex/pr11-consumer-integration": "15e091501e2ebbf7ea463c51c44a87964b2de724"
+}
\ No newline at end of file
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/candidate-sources.csv b/docs/refactoring/evidence/review-2026-10-29/inla/docker/candidate-sources.csv
new file mode 100644
index 0000000..bb8f149
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/candidate-sources.csv
@@ -0,0 +1,22 @@
+"file","md5"
+"R/adjust_incidence_functions.R","ace1a8f7edefeb4f30cf9b270bd54a6e"
+"R/alert_functions.R","ee0e0f4af1e1ddfcb3b5bc22aee308bd"
+"R/AlertTools.R","914a6e16ea0a0082ce67a633412be6db"
+"R/api.R","8278aeb8597c696f643534a404e6efcd"
+"R/auxfun_for_Rt.R","8891b161e29b050a5cc3a5195d57fdc8"
+"R/core_pipeline.R","7166c9ad0da9d4e4d59d0ade8ff640ee"
+"R/data_repository.R","a4d0d7caffb3a498c46107cb6aa0b64c"
+"R/data.R","59f06e0b4bcdc661c36257c2e76bc053"
+"R/dengue-mem.R","c3011ac10b0c40e288db8e8fac2d996b"
+"R/epiweek.R","f7f1a39d433ee2240e193a8e6948bf9b"
+"R/get_timeseries.R","1959852ae906cf506b97b64c5eec2712"
+"R/infodengue_apply_mem.R","47f753f023c0fdd6670741fe6db8a722"
+"R/nowcasting_fun.R","c60affcefca4e054ea63e00595cb0712"
+"R/Rt_functions.R","66e74eba008a95aa92c834671707ebf3"
+"R/utility_tools.R","25a0b36f3b3eeeca089e602f809c2844"
+"tests/reference/inla-reference-validation.R","3e50158dd9d5594ba9372d11a64557b3"
+"tests/reference/inla-validation.R","f40d55756dbe0e9f9e432d31cbf47fe5"
+"tests/testthat/test-inla-consumer.R","749a0db4cd0880c98e31430d6c5b28b7"
+"tests/testthat/test-inla-integration.R","9d53aaa9d266fe0946f4b176acfbeddd"
+"tests/testthat/test-inla-reference.R","d4c43bdbcc095d113f68f3959c43a255"
+"tests/reference/frame-comparison.R","dc37d269ef2049d9723ca479236216a2"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/environment.txt b/docs/refactoring/evidence/review-2026-10-29/inla/docker/environment.txt
new file mode 100644
index 0000000..7fb9753
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/environment.txt
@@ -0,0 +1,29 @@
+R version 4.6.1 (2026-06-24)
+Platform: aarch64-unknown-linux-gnu
+Running under: Ubuntu 24.04.4 LTS
+
+Matrix products: default
+BLAS: /usr/lib/aarch64-linux-gnu/blas/libblas.so.3.12.0
+LAPACK: /usr/lib/aarch64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
+
+locale:
+ [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
+ [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
+ [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
+ [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
+ [9] LC_ADDRESS=C LC_TELEPHONE=C
+[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
+
+time zone: UTC
+tzcode source: system (glibc)
+
+attached base packages:
+[1] stats graphics grDevices datasets utils methods base
+
+loaded via a namespace (and not attached):
+ [1] fmesher_0.8.0 Matrix_1.7-6 lattice_0.23-1 e1071_1.7-17
+ [5] INLA_25.12.16 splines_4.6.1 bspm_0.5.8 KernSmooth_2.23-27
+ [9] lifecycle_1.0.5 classInt_0.4-11 sf_1.1-3 cli_3.6.6
+[13] grid_4.6.1 DBI_1.3.0 withr_3.0.3 proxy_0.4-29
+[17] class_7.3-24 compiler_4.6.1 tools_4.6.1 Rcpp_1.1.2
+[21] otel_0.2.0 rlang_1.3.0 units_1.0-1
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-1.csv b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-1.csv
new file mode 100644
index 0000000..2411e78
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-1.csv
@@ -0,0 +1,59 @@
+"section","metric","rows","differences","max_abs_difference","tolerance","status"
+"data","SE",240,0,0,1e-07,"match"
+"data","CID10",240,0,NA,0,"match"
+"data","casos",240,0,0,1e-07,"match"
+"data","cas_prov",240,0,0,1e-07,"match"
+"data","cas_lab",240,0,0,1e-07,"match"
+"data","localidade",240,0,0,1e-07,"match"
+"data","nome",240,0,NA,0,"match"
+"data","pop",240,0,0,1e-07,"match"
+"data","cidade",240,0,0,1e-07,"match"
+"data","temp_min",240,0,0,1e-07,"match"
+"data","temp_med",240,0,0,1e-07,"match"
+"data","temp_max",240,0,0,1e-07,"match"
+"data","umid_min",240,0,0,1e-07,"match"
+"data","umid_med",240,0,0,1e-07,"match"
+"data","umid_max",240,0,0,1e-07,"match"
+"data","tweet",240,0,0,1e-07,"match"
+"data","inc",240,0,0,1e-07,"match"
+"data","tcasesICmin",240,0,0,1e-07,"match"
+"data","tcasesmed",240,0,0,1e-07,"match"
+"data","tcasesICmax",240,0,0,1e-07,"match"
+"data","Rt",240,0,0,1e-07,"match"
+"data","lwr",240,0,0,1e-07,"match"
+"data","upr",240,0,0,1e-07,"match"
+"data","p1",240,0,0,1e-07,"match"
+"alerts","cytrue",240,0,0,1e-07,"match"
+"alerts","nytrue",240,0,0,1e-07,"match"
+"alerts","cotrue",240,0,0,1e-07,"match"
+"alerts","notrue",240,0,0,1e-07,"match"
+"alerts","crtrue",240,0,0,1e-07,"match"
+"alerts","nrtrue",240,0,0,1e-07,"match"
+"alerts","level",240,0,0,1e-07,"match"
+"history","data_iniSE",240,0,NA,0,"match"
+"history","SE",240,0,0,1e-07,"match"
+"history","CID10",240,0,NA,0,"match"
+"history","casos",240,0,0,1e-07,"match"
+"history","casos_est",240,0,0,1e-07,"match"
+"history","casos_est_min",240,0,0,1e-07,"match"
+"history","casos_est_max",240,0,0,1e-07,"match"
+"history","municipio_geocodigo",240,0,0,1e-07,"match"
+"history","casprov",240,0,0,1e-07,"match"
+"history","p_rt1",240,0,0,1e-07,"match"
+"history","p_inc100k",240,0,0,1e-07,"match"
+"history","Localidade_id",240,0,0,1e-07,"match"
+"history","nivel",240,0,0,1e-07,"match"
+"history","id",240,0,NA,0,"match"
+"history","versao_modelo",240,0,NA,0,"match"
+"history","municipio_nome",240,0,NA,0,"match"
+"history","Rt",240,0,0,1e-07,"match"
+"history","pop",240,0,0,1e-07,"match"
+"history","temp_min",240,0,0,1e-07,"match"
+"history","temp_med",240,0,0,1e-07,"match"
+"history","temp_max",240,0,0,1e-07,"match"
+"history","umid_min",240,0,0,1e-07,"match"
+"history","umid_med",240,0,0,1e-07,"match"
+"history","umid_max",240,0,0,1e-07,"match"
+"history","receptivo",240,0,0,1e-07,"match"
+"history","transmissao",240,0,0,1e-07,"match"
+"history","nivel_inc",240,0,0,1e-07,"match"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-1.rds b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-1.rds
new file mode 100644
index 0000000..350d046
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-1.rds differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-2.csv b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-2.csv
new file mode 100644
index 0000000..2411e78
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-2.csv
@@ -0,0 +1,59 @@
+"section","metric","rows","differences","max_abs_difference","tolerance","status"
+"data","SE",240,0,0,1e-07,"match"
+"data","CID10",240,0,NA,0,"match"
+"data","casos",240,0,0,1e-07,"match"
+"data","cas_prov",240,0,0,1e-07,"match"
+"data","cas_lab",240,0,0,1e-07,"match"
+"data","localidade",240,0,0,1e-07,"match"
+"data","nome",240,0,NA,0,"match"
+"data","pop",240,0,0,1e-07,"match"
+"data","cidade",240,0,0,1e-07,"match"
+"data","temp_min",240,0,0,1e-07,"match"
+"data","temp_med",240,0,0,1e-07,"match"
+"data","temp_max",240,0,0,1e-07,"match"
+"data","umid_min",240,0,0,1e-07,"match"
+"data","umid_med",240,0,0,1e-07,"match"
+"data","umid_max",240,0,0,1e-07,"match"
+"data","tweet",240,0,0,1e-07,"match"
+"data","inc",240,0,0,1e-07,"match"
+"data","tcasesICmin",240,0,0,1e-07,"match"
+"data","tcasesmed",240,0,0,1e-07,"match"
+"data","tcasesICmax",240,0,0,1e-07,"match"
+"data","Rt",240,0,0,1e-07,"match"
+"data","lwr",240,0,0,1e-07,"match"
+"data","upr",240,0,0,1e-07,"match"
+"data","p1",240,0,0,1e-07,"match"
+"alerts","cytrue",240,0,0,1e-07,"match"
+"alerts","nytrue",240,0,0,1e-07,"match"
+"alerts","cotrue",240,0,0,1e-07,"match"
+"alerts","notrue",240,0,0,1e-07,"match"
+"alerts","crtrue",240,0,0,1e-07,"match"
+"alerts","nrtrue",240,0,0,1e-07,"match"
+"alerts","level",240,0,0,1e-07,"match"
+"history","data_iniSE",240,0,NA,0,"match"
+"history","SE",240,0,0,1e-07,"match"
+"history","CID10",240,0,NA,0,"match"
+"history","casos",240,0,0,1e-07,"match"
+"history","casos_est",240,0,0,1e-07,"match"
+"history","casos_est_min",240,0,0,1e-07,"match"
+"history","casos_est_max",240,0,0,1e-07,"match"
+"history","municipio_geocodigo",240,0,0,1e-07,"match"
+"history","casprov",240,0,0,1e-07,"match"
+"history","p_rt1",240,0,0,1e-07,"match"
+"history","p_inc100k",240,0,0,1e-07,"match"
+"history","Localidade_id",240,0,0,1e-07,"match"
+"history","nivel",240,0,0,1e-07,"match"
+"history","id",240,0,NA,0,"match"
+"history","versao_modelo",240,0,NA,0,"match"
+"history","municipio_nome",240,0,NA,0,"match"
+"history","Rt",240,0,0,1e-07,"match"
+"history","pop",240,0,0,1e-07,"match"
+"history","temp_min",240,0,0,1e-07,"match"
+"history","temp_med",240,0,0,1e-07,"match"
+"history","temp_max",240,0,0,1e-07,"match"
+"history","umid_min",240,0,0,1e-07,"match"
+"history","umid_med",240,0,0,1e-07,"match"
+"history","umid_max",240,0,0,1e-07,"match"
+"history","receptivo",240,0,0,1e-07,"match"
+"history","transmissao",240,0,0,1e-07,"match"
+"history","nivel_inc",240,0,0,1e-07,"match"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-2.rds b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-2.rds
new file mode 100644
index 0000000..6c765b1
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/docker/parallel-threads-2.rds differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/reference-comparison.csv b/docs/refactoring/evidence/review-2026-10-29/inla/docker/reference-comparison.csv
new file mode 100644
index 0000000..1acda3a
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/reference-comparison.csv
@@ -0,0 +1,59 @@
+"section","metric","rows","differences","max_abs_difference","tolerance","status"
+"data","SE",120,0,0,1e-07,"match"
+"data","cidade",120,0,0,1e-07,"match"
+"data","CID10",120,0,NA,0,"match"
+"data","casos",120,0,0,1e-07,"match"
+"data","cas_prov",120,0,0,1e-07,"match"
+"data","cas_lab",120,0,0,1e-07,"match"
+"data","localidade",120,0,0,1e-07,"match"
+"data","nome",120,0,NA,0,"match"
+"data","pop",120,0,0,1e-07,"match"
+"data","temp_min",120,0,0,1e-07,"match"
+"data","temp_med",120,0,0,1e-07,"match"
+"data","temp_max",120,0,0,1e-07,"match"
+"data","umid_min",120,0,0,1e-07,"match"
+"data","umid_med",120,0,0,1e-07,"match"
+"data","umid_max",120,0,0,1e-07,"match"
+"data","tweet",120,0,0,1e-07,"match"
+"data","inc",120,0,0,1e-07,"match"
+"data","tcasesICmin",120,0,0,1e-07,"match"
+"data","tcasesmed",120,0,0,1e-07,"match"
+"data","tcasesICmax",120,0,0,1e-07,"match"
+"data","Rt",120,0,0,1e-07,"match"
+"data","lwr",120,0,0,1e-07,"match"
+"data","upr",120,0,0,1e-07,"match"
+"data","p1",120,0,0,1e-07,"match"
+"alerts","cytrue",120,0,0,1e-07,"match"
+"alerts","nytrue",120,0,0,1e-07,"match"
+"alerts","cotrue",120,0,0,1e-07,"match"
+"alerts","notrue",120,0,0,1e-07,"match"
+"alerts","crtrue",120,0,0,1e-07,"match"
+"alerts","nrtrue",120,0,0,1e-07,"match"
+"alerts","level",120,0,0,1e-07,"match"
+"history","data_iniSE",120,0,NA,0,"match"
+"history","SE",120,0,0,1e-07,"match"
+"history","CID10",120,0,NA,0,"match"
+"history","casos",120,0,0,1e-07,"match"
+"history","casos_est",120,0,0,1e-07,"match"
+"history","casos_est_min",120,0,0,1e-07,"match"
+"history","casos_est_max",120,0,0,1e-07,"match"
+"history","municipio_geocodigo",120,0,0,1e-07,"match"
+"history","casprov",120,0,0,1e-07,"match"
+"history","p_rt1",120,0,0,1e-07,"match"
+"history","p_inc100k",120,0,0,1e-07,"match"
+"history","Localidade_id",120,0,0,1e-07,"match"
+"history","nivel",120,0,0,1e-07,"match"
+"history","id",120,0,NA,0,"match"
+"history","versao_modelo",120,0,NA,0,"match"
+"history","municipio_nome",120,0,NA,0,"match"
+"history","Rt",120,0,0,1e-07,"match"
+"history","pop",120,0,0,1e-07,"match"
+"history","temp_min",120,0,0,1e-07,"match"
+"history","temp_med",120,0,0,1e-07,"match"
+"history","temp_max",120,0,0,1e-07,"match"
+"history","umid_min",120,0,0,1e-07,"match"
+"history","umid_med",120,0,0,1e-07,"match"
+"history","umid_max",120,0,0,1e-07,"match"
+"history","receptivo",120,0,0,1e-07,"match"
+"history","transmissao",120,0,0,1e-07,"match"
+"history","nivel_inc",120,0,0,1e-07,"match"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/reference-comparison.rds b/docs/refactoring/evidence/review-2026-10-29/inla/docker/reference-comparison.rds
new file mode 100644
index 0000000..0d9ed33
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/docker/reference-comparison.rds differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/state.RData b/docs/refactoring/evidence/review-2026-10-29/inla/docker/state.RData
new file mode 100644
index 0000000..1bd42b3
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/docker/state.RData differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/state.sql b/docs/refactoring/evidence/review-2026-10-29/inla/docker/state.sql
new file mode 100644
index 0000000..b96770d
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/state.sql
@@ -0,0 +1 @@
+INSERT INTO "Municipio"."Historico_alerta" ("SE", "data_iniSE", "casos_est", "casos_est_min", "casos_est_max", "casos", "casprov", "municipio_geocodigo", "p_rt1", "p_inc100k", "Localidade_id", "nivel", "id", "versao_modelo", "municipio_nome", "Rt", "pop", "tempmin", "tempmed", "tempmax", "umidmin", "umidmed", "umidmax", "receptivo", "transmissao", "nivel_inc") VALUES (201952, '2019-12-22', 14, 14, 14, 14, 14, 3303302, 0, 14, 0, 1, '330330220195220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202001, '2019-12-29', 15, 15, 15, 15, 15, 3303302, 0, 15, 0, 1, '330330220200120755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202002, '2020-01-05', 16, 16, 16, 16, 16, 3303302, 0, 16, 0, 1, '330330220200220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202003, '2020-01-12', 14, 14, 14, 14, 14, 3303302, 0, 14, 0, 1, '330330220200320755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202004, '2020-01-19', 15, 15, 15, 15, 15, 3303302, 0, 15, 0, 1, '330330220200420755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202005, '2020-01-26', 16, 16, 16, 16, 16, 3303302, 0.585155576454341, 16, 0, 1, '330330220200520755', '2026-10-29', 'Municipio Fixture', 1.07947279605036, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202006, '2020-02-02', 14, 14, 14, 14, 14, 3303302, 0.430270199735111, 14, 0, 1, '330330220200620755', '2026-10-29', 'Municipio Fixture', 0.937625389417838, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202007, '2020-02-09', 15, 15, 15, 15, 15, 3303302, 0.497128590424369, 15, 0, 1, '330330220200720755', '2026-10-29', 'Municipio Fixture', 0.99741315124792, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202008, '2020-02-16', 16, 16, 16, 16, 16, 3303302, 0.584998493868361, 16, 0, 1, '330330220200820755', '2026-10-29', 'Municipio Fixture', 1.07931524150169, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202009, '2020-02-23', 14, 14, 14, 14, 14, 3303302, 0.430268459226088, 14, 0, 1, '330330220200920755', '2026-10-29', 'Municipio Fixture', 0.937623889932954, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202010, '2020-03-01', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202011, '2020-03-08', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220201120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202012, '2020-03-15', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220201220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202013, '2020-03-22', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202014, '2020-03-29', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220201420755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202015, '2020-04-05', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220201520755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202016, '2020-04-12', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201620755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202017, '2020-04-19', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220201720755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202018, '2020-04-26', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220201820755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202019, '2020-05-03', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201920755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202020, '2020-05-10', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202020755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202021, '2020-05-17', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220202120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202022, '2020-05-24', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220202220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202023, '2020-05-31', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202320755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202024, '2020-06-07', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220202420755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202025, '2020-06-14', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220202520755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202026, '2020-06-21', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202620755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202027, '2020-06-28', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220202720755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202028, '2020-07-05', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220202820755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202029, '2020-07-12', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202920755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202030, '2020-07-19', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203020755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202031, '2020-07-26', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220203120755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202032, '2020-08-02', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220203220755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202033, '2020-08-09', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203320755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202034, '2020-08-16', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220203420755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202035, '2020-08-23', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220203520755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202036, '2020-08-30', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203620755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202037, '2020-09-06', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220203720755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202038, '2020-09-13', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220203820755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202039, '2020-09-20', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203920755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202040, '2020-09-27', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202041, '2020-10-04', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220204120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202042, '2020-10-11', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220204220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202043, '2020-10-18', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202044, '2020-10-25', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220204420755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202045, '2020-11-01', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220204520755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202046, '2020-11-08', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204620755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202047, '2020-11-15', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220204720755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202048, '2020-11-22', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220204820755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202049, '2020-11-29', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204920755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202050, '2020-12-06', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220205020755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202051, '2020-12-13', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220205120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202052, '2020-12-20', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220205220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202053, '2020-12-27', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220205320755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202101, '2021-01-03', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220210120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202102, '2021-01-10', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220210220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202103, '2021-01-17', 15, 12, 19, 12, 12, 3303302, 0.517033123402467, 15, 0, 1, '330330220210320755', '2026-10-29', 'Municipio Fixture', 1.01555677748553, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202104, '2021-01-24', 15, 10, 20, 9, 9, 3303302, 0.519030342033729, 15, 0, 1, '330330220210420755', '2026-10-29', 'Municipio Fixture', 1.01740574995763, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202105, '2021-01-31', 15, 10, 22, 6, 6, 3303302, 0.50873734692435, 15, 0, 1, '330330220210520755', '2026-10-29', 'Municipio Fixture', 1.00793365342852, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202106, '2021-02-07', 15, 8, 23, 3, 3, 3303302, 0.50538387054848, 15, 0, 1, '330330220210620755', '2026-10-29', 'Municipio Fixture', 1.00487737435887, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (201952, '2019-12-22', 16, 16, 16, 16, 16, 3304557, 0, 16, 0, 1, '330455720195220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202001, '2019-12-29', 14, 14, 14, 14, 14, 3304557, 0, 14, 0, 1, '330455720200120755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202002, '2020-01-05', 15, 15, 15, 15, 15, 3304557, 0, 15, 0, 1, '330455720200220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202003, '2020-01-12', 16, 16, 16, 16, 16, 3304557, 0, 16, 0, 1, '330455720200320755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202004, '2020-01-19', 14, 14, 14, 14, 14, 3304557, 0, 14, 0, 1, '330455720200420755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202005, '2020-01-26', 15, 15, 15, 15, 15, 3304557, 0.497278197540103, 15, 0, 1, '330455720200520755', '2026-10-29', 'Municipio Fixture', 0.997547688552044, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202006, '2020-02-02', 16, 16, 16, 16, 16, 3304557, 0.585000119093189, 16, 0, 1, '330455720200620755', '2026-10-29', 'Municipio Fixture', 1.07931687136424, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202007, '2020-02-09', 14, 14, 14, 14, 14, 3304557, 0.430268465878414, 14, 0, 1, '330455720200720755', '2026-10-29', 'Municipio Fixture', 0.937623895664067, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202008, '2020-02-16', 15, 15, 15, 15, 15, 3304557, 0.497128583254012, 15, 0, 1, '330455720200820755', '2026-10-29', 'Municipio Fixture', 0.997413144800466, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202009, '2020-02-23', 16, 16, 16, 16, 16, 3304557, 0.584998493857749, 16, 0, 1, '330455720200920755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202010, '2020-03-01', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201020755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202011, '2020-03-08', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720201120755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202012, '2020-03-15', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720201220755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202013, '2020-03-22', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201320755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202014, '2020-03-29', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720201420755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202015, '2020-04-05', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720201520755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202016, '2020-04-12', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201620755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202017, '2020-04-19', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720201720755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202018, '2020-04-26', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720201820755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202019, '2020-05-03', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201920755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202020, '2020-05-10', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202021, '2020-05-17', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720202120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202022, '2020-05-24', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720202220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202023, '2020-05-31', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202024, '2020-06-07', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720202420755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202025, '2020-06-14', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720202520755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202026, '2020-06-21', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202620755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202027, '2020-06-28', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720202720755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202028, '2020-07-05', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720202820755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202029, '2020-07-12', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202920755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202030, '2020-07-19', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203020755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202031, '2020-07-26', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720203120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202032, '2020-08-02', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720203220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202033, '2020-08-09', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203320755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202034, '2020-08-16', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720203420755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202035, '2020-08-23', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720203520755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202036, '2020-08-30', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203620755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202037, '2020-09-06', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720203720755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202038, '2020-09-13', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720203820755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202039, '2020-09-20', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203920755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202040, '2020-09-27', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204020755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202041, '2020-10-04', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720204120755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202042, '2020-10-11', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720204220755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202043, '2020-10-18', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204320755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202044, '2020-10-25', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720204420755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202045, '2020-11-01', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720204520755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202046, '2020-11-08', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204620755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202047, '2020-11-15', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720204720755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202048, '2020-11-22', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720204820755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202049, '2020-11-29', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204920755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202050, '2020-12-06', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720205020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202051, '2020-12-13', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720205120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202052, '2020-12-20', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720205220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202053, '2020-12-27', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720205320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202101, '2021-01-03', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720210120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202102, '2021-01-10', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720210220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202103, '2021-01-17', 16, 13, 20, 13, 13, 3304557, 0.565485280421632, 16, 0, 1, '330455720210320755', '2026-10-29', 'Municipio Fixture', 1.06010149821127, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202104, '2021-01-24', 15, 10, 21, 9, 9, 3304557, 0.499099583064595, 15, 0, 1, '330455720210420755', '2026-10-29', 'Municipio Fixture', 0.999187750085643, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202105, '2021-01-31', 14, 8, 21, 5, 5, 3304557, 0.418888584694345, 14, 0, 1, '330455720210520755', '2026-10-29', 'Municipio Fixture', 0.927869313777229, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202106, '2021-02-07', 16, 9, 24, 4, 4, 3304557, 0.576886378324967, 16, 0, 1, '330455720210620755', '2026-10-29', 'Municipio Fixture', 1.07124281053221, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1) ON CONFLICT ("SE", "municipio_geocodigo", "Localidade_id") DO UPDATE SET "data_iniSE" = excluded."data_iniSE", "casos_est" = excluded."casos_est", "casos_est_min" = excluded."casos_est_min", "casos_est_max" = excluded."casos_est_max", "casos" = excluded."casos", "casprov" = excluded."casprov", "p_rt1" = excluded."p_rt1", "p_inc100k" = excluded."p_inc100k", "nivel" = excluded."nivel", "id" = excluded."id", "versao_modelo" = excluded."versao_modelo", "municipio_nome" = excluded."municipio_nome", "Rt" = excluded."Rt", "pop" = excluded."pop", "tempmin" = excluded."tempmin", "tempmed" = excluded."tempmed", "tempmax" = excluded."tempmax", "umidmin" = excluded."umidmin", "umidmed" = excluded."umidmed", "umidmax" = excluded."umidmax", "receptivo" = excluded."receptivo", "transmissao" = excluded."transmissao", "nivel_inc" = excluded."nivel_inc";
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/docker/test-results.csv b/docs/refactoring/evidence/review-2026-10-29/inla/docker/test-results.csv
new file mode 100644
index 0000000..4eb31d5
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/docker/test-results.csv
@@ -0,0 +1,5 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-inla-consumer.R","inla-consumer","real Bayesian consumer fallback isolates failures and preserves artifacts",7,0,FALSE,FALSE,0,10.686,0.086,13.956,7
+"test-inla-integration.R","inla-integration","real INLA preserves repeated and municipal-parallel results",4,0,FALSE,FALSE,0,32.346,0.352,62.207,4
+"test-inla-integration.R","inla-integration","terminated municipal workers cannot be mistaken for complete output",2,0,FALSE,FALSE,0,0.00800000000000267,0.005,0.0169999999999959,2
+"test-inla-reference.R","inla-reference","real INLA agrees with pinned calculations at the historical fitting budget",1,0,FALSE,FALSE,0,11.668,0.154,16.156,1
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/candidate-sources.csv b/docs/refactoring/evidence/review-2026-10-29/inla/host/candidate-sources.csv
new file mode 100644
index 0000000..bb8f149
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/candidate-sources.csv
@@ -0,0 +1,22 @@
+"file","md5"
+"R/adjust_incidence_functions.R","ace1a8f7edefeb4f30cf9b270bd54a6e"
+"R/alert_functions.R","ee0e0f4af1e1ddfcb3b5bc22aee308bd"
+"R/AlertTools.R","914a6e16ea0a0082ce67a633412be6db"
+"R/api.R","8278aeb8597c696f643534a404e6efcd"
+"R/auxfun_for_Rt.R","8891b161e29b050a5cc3a5195d57fdc8"
+"R/core_pipeline.R","7166c9ad0da9d4e4d59d0ade8ff640ee"
+"R/data_repository.R","a4d0d7caffb3a498c46107cb6aa0b64c"
+"R/data.R","59f06e0b4bcdc661c36257c2e76bc053"
+"R/dengue-mem.R","c3011ac10b0c40e288db8e8fac2d996b"
+"R/epiweek.R","f7f1a39d433ee2240e193a8e6948bf9b"
+"R/get_timeseries.R","1959852ae906cf506b97b64c5eec2712"
+"R/infodengue_apply_mem.R","47f753f023c0fdd6670741fe6db8a722"
+"R/nowcasting_fun.R","c60affcefca4e054ea63e00595cb0712"
+"R/Rt_functions.R","66e74eba008a95aa92c834671707ebf3"
+"R/utility_tools.R","25a0b36f3b3eeeca089e602f809c2844"
+"tests/reference/inla-reference-validation.R","3e50158dd9d5594ba9372d11a64557b3"
+"tests/reference/inla-validation.R","f40d55756dbe0e9f9e432d31cbf47fe5"
+"tests/testthat/test-inla-consumer.R","749a0db4cd0880c98e31430d6c5b28b7"
+"tests/testthat/test-inla-integration.R","9d53aaa9d266fe0946f4b176acfbeddd"
+"tests/testthat/test-inla-reference.R","d4c43bdbcc095d113f68f3959c43a255"
+"tests/reference/frame-comparison.R","dc37d269ef2049d9723ca479236216a2"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/environment.txt b/docs/refactoring/evidence/review-2026-10-29/inla/host/environment.txt
new file mode 100644
index 0000000..18251de
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/environment.txt
@@ -0,0 +1,24 @@
+R version 4.4.3 (2025-02-28)
+Platform: aarch64-apple-darwin20
+Running under: macOS 26.6.2
+
+Matrix products: default
+BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib
+LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
+
+locale:
+[1] C.UTF-8/C.UTF-8/C.UTF-8/C/C.UTF-8/C.UTF-8
+
+time zone: America/Maceio
+tzcode source: internal
+
+attached base packages:
+[1] stats graphics grDevices utils datasets methods base
+
+loaded via a namespace (and not attached):
+ [1] fmesher_0.7.0 Matrix_1.7-5 lattice_0.22-9 magrittr_2.0.4
+ [5] e1071_1.7-17 INLA_24.12.11 splines_4.4.3 KernSmooth_2.23-26
+ [9] lifecycle_1.0.5 classInt_0.4-11 sf_1.1-0 cli_3.6.5
+[13] grid_4.4.3 DBI_1.3.0 withr_3.0.2 proxy_0.4-29
+[17] class_7.3-23 compiler_4.4.3 tools_4.4.3 Rcpp_1.1.1
+[21] otel_0.2.0 rlang_1.1.7 units_1.0-1
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-1.csv b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-1.csv
new file mode 100644
index 0000000..2411e78
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-1.csv
@@ -0,0 +1,59 @@
+"section","metric","rows","differences","max_abs_difference","tolerance","status"
+"data","SE",240,0,0,1e-07,"match"
+"data","CID10",240,0,NA,0,"match"
+"data","casos",240,0,0,1e-07,"match"
+"data","cas_prov",240,0,0,1e-07,"match"
+"data","cas_lab",240,0,0,1e-07,"match"
+"data","localidade",240,0,0,1e-07,"match"
+"data","nome",240,0,NA,0,"match"
+"data","pop",240,0,0,1e-07,"match"
+"data","cidade",240,0,0,1e-07,"match"
+"data","temp_min",240,0,0,1e-07,"match"
+"data","temp_med",240,0,0,1e-07,"match"
+"data","temp_max",240,0,0,1e-07,"match"
+"data","umid_min",240,0,0,1e-07,"match"
+"data","umid_med",240,0,0,1e-07,"match"
+"data","umid_max",240,0,0,1e-07,"match"
+"data","tweet",240,0,0,1e-07,"match"
+"data","inc",240,0,0,1e-07,"match"
+"data","tcasesICmin",240,0,0,1e-07,"match"
+"data","tcasesmed",240,0,0,1e-07,"match"
+"data","tcasesICmax",240,0,0,1e-07,"match"
+"data","Rt",240,0,0,1e-07,"match"
+"data","lwr",240,0,0,1e-07,"match"
+"data","upr",240,0,0,1e-07,"match"
+"data","p1",240,0,0,1e-07,"match"
+"alerts","cytrue",240,0,0,1e-07,"match"
+"alerts","nytrue",240,0,0,1e-07,"match"
+"alerts","cotrue",240,0,0,1e-07,"match"
+"alerts","notrue",240,0,0,1e-07,"match"
+"alerts","crtrue",240,0,0,1e-07,"match"
+"alerts","nrtrue",240,0,0,1e-07,"match"
+"alerts","level",240,0,0,1e-07,"match"
+"history","data_iniSE",240,0,NA,0,"match"
+"history","SE",240,0,0,1e-07,"match"
+"history","CID10",240,0,NA,0,"match"
+"history","casos",240,0,0,1e-07,"match"
+"history","casos_est",240,0,0,1e-07,"match"
+"history","casos_est_min",240,0,0,1e-07,"match"
+"history","casos_est_max",240,0,0,1e-07,"match"
+"history","municipio_geocodigo",240,0,0,1e-07,"match"
+"history","casprov",240,0,0,1e-07,"match"
+"history","p_rt1",240,0,0,1e-07,"match"
+"history","p_inc100k",240,0,0,1e-07,"match"
+"history","Localidade_id",240,0,0,1e-07,"match"
+"history","nivel",240,0,0,1e-07,"match"
+"history","id",240,0,NA,0,"match"
+"history","versao_modelo",240,0,NA,0,"match"
+"history","municipio_nome",240,0,NA,0,"match"
+"history","Rt",240,0,0,1e-07,"match"
+"history","pop",240,0,0,1e-07,"match"
+"history","temp_min",240,0,0,1e-07,"match"
+"history","temp_med",240,0,0,1e-07,"match"
+"history","temp_max",240,0,0,1e-07,"match"
+"history","umid_min",240,0,0,1e-07,"match"
+"history","umid_med",240,0,0,1e-07,"match"
+"history","umid_max",240,0,0,1e-07,"match"
+"history","receptivo",240,0,0,1e-07,"match"
+"history","transmissao",240,0,0,1e-07,"match"
+"history","nivel_inc",240,0,0,1e-07,"match"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-1.rds b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-1.rds
new file mode 100644
index 0000000..f8f1efb
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-1.rds differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-2.csv b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-2.csv
new file mode 100644
index 0000000..2411e78
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-2.csv
@@ -0,0 +1,59 @@
+"section","metric","rows","differences","max_abs_difference","tolerance","status"
+"data","SE",240,0,0,1e-07,"match"
+"data","CID10",240,0,NA,0,"match"
+"data","casos",240,0,0,1e-07,"match"
+"data","cas_prov",240,0,0,1e-07,"match"
+"data","cas_lab",240,0,0,1e-07,"match"
+"data","localidade",240,0,0,1e-07,"match"
+"data","nome",240,0,NA,0,"match"
+"data","pop",240,0,0,1e-07,"match"
+"data","cidade",240,0,0,1e-07,"match"
+"data","temp_min",240,0,0,1e-07,"match"
+"data","temp_med",240,0,0,1e-07,"match"
+"data","temp_max",240,0,0,1e-07,"match"
+"data","umid_min",240,0,0,1e-07,"match"
+"data","umid_med",240,0,0,1e-07,"match"
+"data","umid_max",240,0,0,1e-07,"match"
+"data","tweet",240,0,0,1e-07,"match"
+"data","inc",240,0,0,1e-07,"match"
+"data","tcasesICmin",240,0,0,1e-07,"match"
+"data","tcasesmed",240,0,0,1e-07,"match"
+"data","tcasesICmax",240,0,0,1e-07,"match"
+"data","Rt",240,0,0,1e-07,"match"
+"data","lwr",240,0,0,1e-07,"match"
+"data","upr",240,0,0,1e-07,"match"
+"data","p1",240,0,0,1e-07,"match"
+"alerts","cytrue",240,0,0,1e-07,"match"
+"alerts","nytrue",240,0,0,1e-07,"match"
+"alerts","cotrue",240,0,0,1e-07,"match"
+"alerts","notrue",240,0,0,1e-07,"match"
+"alerts","crtrue",240,0,0,1e-07,"match"
+"alerts","nrtrue",240,0,0,1e-07,"match"
+"alerts","level",240,0,0,1e-07,"match"
+"history","data_iniSE",240,0,NA,0,"match"
+"history","SE",240,0,0,1e-07,"match"
+"history","CID10",240,0,NA,0,"match"
+"history","casos",240,0,0,1e-07,"match"
+"history","casos_est",240,0,0,1e-07,"match"
+"history","casos_est_min",240,0,0,1e-07,"match"
+"history","casos_est_max",240,0,0,1e-07,"match"
+"history","municipio_geocodigo",240,0,0,1e-07,"match"
+"history","casprov",240,0,0,1e-07,"match"
+"history","p_rt1",240,0,0,1e-07,"match"
+"history","p_inc100k",240,0,0,1e-07,"match"
+"history","Localidade_id",240,0,0,1e-07,"match"
+"history","nivel",240,0,0,1e-07,"match"
+"history","id",240,0,NA,0,"match"
+"history","versao_modelo",240,0,NA,0,"match"
+"history","municipio_nome",240,0,NA,0,"match"
+"history","Rt",240,0,0,1e-07,"match"
+"history","pop",240,0,0,1e-07,"match"
+"history","temp_min",240,0,0,1e-07,"match"
+"history","temp_med",240,0,0,1e-07,"match"
+"history","temp_max",240,0,0,1e-07,"match"
+"history","umid_min",240,0,0,1e-07,"match"
+"history","umid_med",240,0,0,1e-07,"match"
+"history","umid_max",240,0,0,1e-07,"match"
+"history","receptivo",240,0,0,1e-07,"match"
+"history","transmissao",240,0,0,1e-07,"match"
+"history","nivel_inc",240,0,0,1e-07,"match"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-2.rds b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-2.rds
new file mode 100644
index 0000000..d54e9a2
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/host/parallel-threads-2.rds differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/reference-comparison.csv b/docs/refactoring/evidence/review-2026-10-29/inla/host/reference-comparison.csv
new file mode 100644
index 0000000..1acda3a
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/reference-comparison.csv
@@ -0,0 +1,59 @@
+"section","metric","rows","differences","max_abs_difference","tolerance","status"
+"data","SE",120,0,0,1e-07,"match"
+"data","cidade",120,0,0,1e-07,"match"
+"data","CID10",120,0,NA,0,"match"
+"data","casos",120,0,0,1e-07,"match"
+"data","cas_prov",120,0,0,1e-07,"match"
+"data","cas_lab",120,0,0,1e-07,"match"
+"data","localidade",120,0,0,1e-07,"match"
+"data","nome",120,0,NA,0,"match"
+"data","pop",120,0,0,1e-07,"match"
+"data","temp_min",120,0,0,1e-07,"match"
+"data","temp_med",120,0,0,1e-07,"match"
+"data","temp_max",120,0,0,1e-07,"match"
+"data","umid_min",120,0,0,1e-07,"match"
+"data","umid_med",120,0,0,1e-07,"match"
+"data","umid_max",120,0,0,1e-07,"match"
+"data","tweet",120,0,0,1e-07,"match"
+"data","inc",120,0,0,1e-07,"match"
+"data","tcasesICmin",120,0,0,1e-07,"match"
+"data","tcasesmed",120,0,0,1e-07,"match"
+"data","tcasesICmax",120,0,0,1e-07,"match"
+"data","Rt",120,0,0,1e-07,"match"
+"data","lwr",120,0,0,1e-07,"match"
+"data","upr",120,0,0,1e-07,"match"
+"data","p1",120,0,0,1e-07,"match"
+"alerts","cytrue",120,0,0,1e-07,"match"
+"alerts","nytrue",120,0,0,1e-07,"match"
+"alerts","cotrue",120,0,0,1e-07,"match"
+"alerts","notrue",120,0,0,1e-07,"match"
+"alerts","crtrue",120,0,0,1e-07,"match"
+"alerts","nrtrue",120,0,0,1e-07,"match"
+"alerts","level",120,0,0,1e-07,"match"
+"history","data_iniSE",120,0,NA,0,"match"
+"history","SE",120,0,0,1e-07,"match"
+"history","CID10",120,0,NA,0,"match"
+"history","casos",120,0,0,1e-07,"match"
+"history","casos_est",120,0,0,1e-07,"match"
+"history","casos_est_min",120,0,0,1e-07,"match"
+"history","casos_est_max",120,0,0,1e-07,"match"
+"history","municipio_geocodigo",120,0,0,1e-07,"match"
+"history","casprov",120,0,0,1e-07,"match"
+"history","p_rt1",120,0,0,1e-07,"match"
+"history","p_inc100k",120,0,0,1e-07,"match"
+"history","Localidade_id",120,0,0,1e-07,"match"
+"history","nivel",120,0,0,1e-07,"match"
+"history","id",120,0,NA,0,"match"
+"history","versao_modelo",120,0,NA,0,"match"
+"history","municipio_nome",120,0,NA,0,"match"
+"history","Rt",120,0,0,1e-07,"match"
+"history","pop",120,0,0,1e-07,"match"
+"history","temp_min",120,0,0,1e-07,"match"
+"history","temp_med",120,0,0,1e-07,"match"
+"history","temp_max",120,0,0,1e-07,"match"
+"history","umid_min",120,0,0,1e-07,"match"
+"history","umid_med",120,0,0,1e-07,"match"
+"history","umid_max",120,0,0,1e-07,"match"
+"history","receptivo",120,0,0,1e-07,"match"
+"history","transmissao",120,0,0,1e-07,"match"
+"history","nivel_inc",120,0,0,1e-07,"match"
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/reference-comparison.rds b/docs/refactoring/evidence/review-2026-10-29/inla/host/reference-comparison.rds
new file mode 100644
index 0000000..2fa81fb
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/host/reference-comparison.rds differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/state.RData b/docs/refactoring/evidence/review-2026-10-29/inla/host/state.RData
new file mode 100644
index 0000000..482ae04
Binary files /dev/null and b/docs/refactoring/evidence/review-2026-10-29/inla/host/state.RData differ
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/state.sql b/docs/refactoring/evidence/review-2026-10-29/inla/host/state.sql
new file mode 100644
index 0000000..8fb3dde
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/state.sql
@@ -0,0 +1 @@
+INSERT INTO "Municipio"."Historico_alerta" ("SE", "data_iniSE", "casos_est", "casos_est_min", "casos_est_max", "casos", "casprov", "municipio_geocodigo", "p_rt1", "p_inc100k", "Localidade_id", "nivel", "id", "versao_modelo", "municipio_nome", "Rt", "pop", "tempmin", "tempmed", "tempmax", "umidmin", "umidmed", "umidmax", "receptivo", "transmissao", "nivel_inc") VALUES (201952, '2019-12-22', 14, 14, 14, 14, 14, 3303302, 0, 14, 0, 1, '330330220195220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202001, '2019-12-29', 15, 15, 15, 15, 15, 3303302, 0, 15, 0, 1, '330330220200120755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202002, '2020-01-05', 16, 16, 16, 16, 16, 3303302, 0, 16, 0, 1, '330330220200220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202003, '2020-01-12', 14, 14, 14, 14, 14, 3303302, 0, 14, 0, 1, '330330220200320755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202004, '2020-01-19', 15, 15, 15, 15, 15, 3303302, 0, 15, 0, 1, '330330220200420755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202005, '2020-01-26', 16, 16, 16, 16, 16, 3303302, 0.585155576454341, 16, 0, 1, '330330220200520755', '2026-10-29', 'Municipio Fixture', 1.07947279605036, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202006, '2020-02-02', 14, 14, 14, 14, 14, 3303302, 0.430270199735111, 14, 0, 1, '330330220200620755', '2026-10-29', 'Municipio Fixture', 0.937625389417838, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202007, '2020-02-09', 15, 15, 15, 15, 15, 3303302, 0.497128590424369, 15, 0, 1, '330330220200720755', '2026-10-29', 'Municipio Fixture', 0.99741315124792, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202008, '2020-02-16', 16, 16, 16, 16, 16, 3303302, 0.584998493868361, 16, 0, 1, '330330220200820755', '2026-10-29', 'Municipio Fixture', 1.07931524150169, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202009, '2020-02-23', 14, 14, 14, 14, 14, 3303302, 0.430268459226088, 14, 0, 1, '330330220200920755', '2026-10-29', 'Municipio Fixture', 0.937623889932954, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202010, '2020-03-01', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202011, '2020-03-08', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220201120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202012, '2020-03-15', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220201220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202013, '2020-03-22', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202014, '2020-03-29', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220201420755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202015, '2020-04-05', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220201520755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202016, '2020-04-12', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201620755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202017, '2020-04-19', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220201720755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202018, '2020-04-26', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220201820755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202019, '2020-05-03', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220201920755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202020, '2020-05-10', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202020755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202021, '2020-05-17', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220202120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202022, '2020-05-24', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220202220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202023, '2020-05-31', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202320755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202024, '2020-06-07', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220202420755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202025, '2020-06-14', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220202520755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202026, '2020-06-21', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202620755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202027, '2020-06-28', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220202720755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202028, '2020-07-05', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220202820755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202029, '2020-07-12', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220202920755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202030, '2020-07-19', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203020755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202031, '2020-07-26', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220203120755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202032, '2020-08-02', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220203220755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202033, '2020-08-09', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203320755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202034, '2020-08-16', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220203420755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202035, '2020-08-23', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220203520755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202036, '2020-08-30', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203620755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202037, '2020-09-06', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220203720755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202038, '2020-09-13', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220203820755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202039, '2020-09-20', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220203920755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202040, '2020-09-27', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202041, '2020-10-04', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220204120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202042, '2020-10-11', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220204220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202043, '2020-10-18', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202044, '2020-10-25', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220204420755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202045, '2020-11-01', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220204520755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202046, '2020-11-08', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204620755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202047, '2020-11-15', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220204720755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202048, '2020-11-22', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220204820755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202049, '2020-11-29', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220204920755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202050, '2020-12-06', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220205020755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202051, '2020-12-13', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220205120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202052, '2020-12-20', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220205220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202053, '2020-12-27', 16, 16, 16, 16, 16, 3303302, 0.584998493857745, 16, 0, 1, '330330220205320755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202101, '2021-01-03', 14, 14, 14, 14, 14, 3303302, 0.430268459226083, 14, 0, 1, '330330220210120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202102, '2021-01-10', 15, 15, 15, 15, 15, 3303302, 0.497128583243901, 15, 0, 1, '330330220210220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202103, '2021-01-17', 15, 12, 19, 12, 12, 3303302, 0.517033123402467, 15, 0, 1, '330330220210320755', '2026-10-29', 'Municipio Fixture', 1.01555677748553, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202104, '2021-01-24', 15, 11, 20, 9, 9, 3303302, 0.519030342033728, 15, 0, 1, '330330220210420755', '2026-10-29', 'Municipio Fixture', 1.01740574995763, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202105, '2021-01-31', 15, 9, 22, 6, 6, 3303302, 0.50873734692435, 15, 0, 1, '330330220210520755', '2026-10-29', 'Municipio Fixture', 1.00793365342852, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202106, '2021-02-07', 15, 8, 23, 3, 3, 3303302, 0.50538387054848, 15, 0, 1, '330330220210620755', '2026-10-29', 'Municipio Fixture', 1.00487737435887, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (201952, '2019-12-22', 16, 16, 16, 16, 16, 3304557, 0, 16, 0, 1, '330455720195220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202001, '2019-12-29', 14, 14, 14, 14, 14, 3304557, 0, 14, 0, 1, '330455720200120755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202002, '2020-01-05', 15, 15, 15, 15, 15, 3304557, 0, 15, 0, 1, '330455720200220755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202003, '2020-01-12', 16, 16, 16, 16, 16, 3304557, 0, 16, 0, 1, '330455720200320755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202004, '2020-01-19', 14, 14, 14, 14, 14, 3304557, 0, 14, 0, 1, '330455720200420755', '2026-10-29', 'Municipio Fixture', 0, 1e+05, 20, 24, 28, 45, 60, 75, 0, NULL, 1), (202005, '2020-01-26', 15, 15, 15, 15, 15, 3304557, 0.497278197540103, 15, 0, 1, '330455720200520755', '2026-10-29', 'Municipio Fixture', 0.997547688552044, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202006, '2020-02-02', 16, 16, 16, 16, 16, 3304557, 0.58500011909319, 16, 0, 1, '330455720200620755', '2026-10-29', 'Municipio Fixture', 1.07931687136424, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202007, '2020-02-09', 14, 14, 14, 14, 14, 3304557, 0.430268465878414, 14, 0, 1, '330455720200720755', '2026-10-29', 'Municipio Fixture', 0.937623895664067, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202008, '2020-02-16', 15, 15, 15, 15, 15, 3304557, 0.497128583254012, 15, 0, 1, '330455720200820755', '2026-10-29', 'Municipio Fixture', 0.997413144800466, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202009, '2020-02-23', 16, 16, 16, 16, 16, 3304557, 0.58499849385775, 16, 0, 1, '330455720200920755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202010, '2020-03-01', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201020755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202011, '2020-03-08', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720201120755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202012, '2020-03-15', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720201220755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202013, '2020-03-22', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201320755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202014, '2020-03-29', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720201420755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202015, '2020-04-05', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720201520755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202016, '2020-04-12', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201620755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202017, '2020-04-19', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720201720755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202018, '2020-04-26', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720201820755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202019, '2020-05-03', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720201920755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202020, '2020-05-10', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202021, '2020-05-17', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720202120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202022, '2020-05-24', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720202220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202023, '2020-05-31', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202024, '2020-06-07', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720202420755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202025, '2020-06-14', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720202520755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202026, '2020-06-21', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202620755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202027, '2020-06-28', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720202720755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202028, '2020-07-05', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720202820755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202029, '2020-07-12', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720202920755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202030, '2020-07-19', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203020755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202031, '2020-07-26', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720203120755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202032, '2020-08-02', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720203220755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202033, '2020-08-09', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203320755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202034, '2020-08-16', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720203420755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202035, '2020-08-23', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720203520755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202036, '2020-08-30', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203620755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202037, '2020-09-06', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720203720755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202038, '2020-09-13', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720203820755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202039, '2020-09-20', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720203920755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202040, '2020-09-27', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204020755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202041, '2020-10-04', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720204120755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202042, '2020-10-11', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720204220755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202043, '2020-10-18', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204320755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202044, '2020-10-25', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720204420755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202045, '2020-11-01', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720204520755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202046, '2020-11-08', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204620755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202047, '2020-11-15', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720204720755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202048, '2020-11-22', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720204820755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202049, '2020-11-29', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720204920755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202050, '2020-12-06', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720205020755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202051, '2020-12-13', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720205120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202052, '2020-12-20', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720205220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202053, '2020-12-27', 15, 15, 15, 15, 15, 3304557, 0.497128583243901, 15, 0, 1, '330455720205320755', '2026-10-29', 'Municipio Fixture', 0.997413144791373, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202101, '2021-01-03', 16, 16, 16, 16, 16, 3304557, 0.584998493857745, 16, 0, 1, '330455720210120755', '2026-10-29', 'Municipio Fixture', 1.07931524149104, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202102, '2021-01-10', 14, 14, 14, 14, 14, 3304557, 0.430268459226083, 14, 0, 1, '330455720210220755', '2026-10-29', 'Municipio Fixture', 0.937623889932949, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202103, '2021-01-17', 16, 13, 20, 13, 13, 3304557, 0.565485280421631, 16, 0, 1, '330455720210320755', '2026-10-29', 'Municipio Fixture', 1.06010149821127, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202104, '2021-01-24', 15, 11, 20, 9, 9, 3304557, 0.499099583064593, 15, 0, 1, '330455720210420755', '2026-10-29', 'Municipio Fixture', 0.999187750085643, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202105, '2021-01-31', 14, 8.975, 21, 5, 5, 3304557, 0.418888584694345, 14, 0, 1, '330455720210520755', '2026-10-29', 'Municipio Fixture', 0.927869313777229, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1), (202106, '2021-02-07', 16, 9, 24, 4, 4, 3304557, 0.576886378324967, 16, 0, 1, '330455720210620755', '2026-10-29', 'Municipio Fixture', 1.07124281053221, 1e+05, 20, 24, 28, 45, 60, 75, 0, 0, 1) ON CONFLICT ("SE", "municipio_geocodigo", "Localidade_id") DO UPDATE SET "data_iniSE" = excluded."data_iniSE", "casos_est" = excluded."casos_est", "casos_est_min" = excluded."casos_est_min", "casos_est_max" = excluded."casos_est_max", "casos" = excluded."casos", "casprov" = excluded."casprov", "p_rt1" = excluded."p_rt1", "p_inc100k" = excluded."p_inc100k", "nivel" = excluded."nivel", "id" = excluded."id", "versao_modelo" = excluded."versao_modelo", "municipio_nome" = excluded."municipio_nome", "Rt" = excluded."Rt", "pop" = excluded."pop", "tempmin" = excluded."tempmin", "tempmed" = excluded."tempmed", "tempmax" = excluded."tempmax", "umidmin" = excluded."umidmin", "umidmed" = excluded."umidmed", "umidmax" = excluded."umidmax", "receptivo" = excluded."receptivo", "transmissao" = excluded."transmissao", "nivel_inc" = excluded."nivel_inc";
diff --git a/docs/refactoring/evidence/review-2026-10-29/inla/host/test-results.csv b/docs/refactoring/evidence/review-2026-10-29/inla/host/test-results.csv
new file mode 100644
index 0000000..11c3e5d
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/inla/host/test-results.csv
@@ -0,0 +1,5 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-inla-consumer.R","inla-consumer","real Bayesian consumer fallback isolates failures and preserves artifacts",7,0,FALSE,FALSE,0,9.201,0.497,25.481,7
+"test-inla-integration.R","inla-integration","real INLA preserves repeated and municipal-parallel results",4,0,FALSE,FALSE,0,26.4,1.829,122.033,4
+"test-inla-integration.R","inla-integration","terminated municipal workers cannot be mistaken for complete output",2,0,FALSE,FALSE,0,0.00500000000000256,0.0169999999999999,0.0240000000000009,2
+"test-inla-reference.R","inla-reference","real INLA agrees with pinned calculations at the historical fitting budget",1,0,FALSE,FALSE,0,8.378,0.52,27.972,1
diff --git a/docs/refactoring/evidence/review-2026-10-29/lint.txt b/docs/refactoring/evidence/review-2026-10-29/lint.txt
new file mode 100644
index 0000000..db210d6
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/lint.txt
@@ -0,0 +1 @@
+ℹ No lints found.
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks.json b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks.json
new file mode 100644
index 0000000..b76cb7a
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks.json
@@ -0,0 +1,48 @@
+[
+ {
+ "pr": 28,
+ "sha": "fe2a2e51ed64aa84e4f5ef9b8e5d26fcde1003f2",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr28-final.csv"
+ },
+ {
+ "pr": 30,
+ "sha": "ce910aa98fe67223e4b5a4f971476f9840a2c3c4",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr30-final.csv"
+ },
+ {
+ "pr": 31,
+ "sha": "46963e79c48cd428bb002cd18d16029507753e97",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr31-final.csv"
+ },
+ {
+ "pr": 32,
+ "sha": "b8d0a64fc6bc2e97f41669ff3e656fc0708d9548",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr32-final.csv"
+ },
+ {
+ "pr": 33,
+ "sha": "aeb282ffa2a597631756f7cac87aa93da8bd58a9",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr33-final.csv"
+ },
+ {
+ "pr": 34,
+ "sha": "056c5e49eed254e427d8882642c73daa0d264270",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr34-final.csv",
+ "inla_exit_code": 0,
+ "inla_evidence": "local-pr34-inla"
+ },
+ {
+ "pr": 36,
+ "sha": "e2ccfd9b3dbaa0474a8853ca55e7802efd40c176",
+ "exit_code": 0,
+ "summary": "local-pr-checks/alerttools-review-local-pr36-final.csv",
+ "inla_exit_code": 0,
+ "inla_evidence": "local-pr36-inla"
+ }
+]
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr28-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr28-final.csv
new file mode 100644
index 0000000..5928982
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr28-final.csv
@@ -0,0 +1,13 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-alert-rules.R","alert-rules","setCriteria validates inputs and returns the legacy structure",5,0,FALSE,FALSE,0,0.036,0.002,0.0389999999999999,5
+"test-alert-rules.R","alert-rules","setCriteria keeps its legacy delay-list default",2,0,FALSE,FALSE,0,0.004,0.001,0.005,2
+"test-alert-rules.R","alert-rules","alert rules preserve output structure and delayed levels",6,0,FALSE,FALSE,0,0.015,0.001,0.017,6
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",9,0,FALSE,FALSE,0,0.0289999999999999,0.00199999999999999,0.031,9
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.056,0.001,0.0579999999999999,2
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.123,0.004,0.128,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.121,0.00199999999999999,0.123,5
+"test-api.R","api","legacy wrappers warn and preserve argument and result adapters",11,0,FALSE,FALSE,0,0.162,0.003,0.164,11
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.056,0.002,0.058,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.0069999999999999,0.001,0.00800000000000001,3
+"test-api.R","api","legacy computational wrappers identify replacements and remain equivalent",10,0,FALSE,FALSE,0,0.0509999999999999,0.001,0.052,10
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.04,0.001,0.042,6
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr30-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr30-final.csv
new file mode 100644
index 0000000..71cb4aa
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr30-final.csv
@@ -0,0 +1,11 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",9,0,FALSE,FALSE,0,0.043,0.002,0.0449999999999999,9
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.081,0.002,0.0830000000000001,2
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.125,0.004,0.129,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.111,0.002,0.113,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.125,0.003,0.128,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.0589999999999999,0.002,0.062,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.006,0.001,0.006,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.0230000000000001,0.002,0.0249999999999999,10
+"test-deprecation-policy.R","deprecation-policy","legacy warnings start at 1.3.0 and execute the lifecycle emitter",4,0,FALSE,FALSE,0,0.0210000000000001,0,0.0209999999999999,4
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0410000000000001,0.001,0.0430000000000001,6
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr31-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr31-final.csv
new file mode 100644
index 0000000..fac169d
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr31-final.csv
@@ -0,0 +1,22 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",14,0,FALSE,FALSE,0,0.055,0.003,0.0589999999999999,14
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.095,0.001,0.097,2
+"test-api.R","api","public computational entry validates canonical keys before joining",4,0,FALSE,FALSE,0,0.012,0.000999999999999994,0.012,4
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.125,0.004,0.129,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.116,0.001,0.119,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.127,0.002,0.13,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.058,0.002,0.0599999999999998,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.00800000000000001,0.001,0.0089999999999999,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.0230000000000001,0.002,0.024,10
+"test-core-pipeline.R","core-pipeline","pure pipeline runs deterministically from in-memory fixtures",10,0,FALSE,FALSE,0,0.0190000000000001,0.002,0.0210000000000001,10
+"test-core-pipeline.R","core-pipeline","pipeline keeps diseases separate within the same municipality",15,0,FALSE,FALSE,0,0.06,0.00299999999999999,0.063,15
+"test-core-pipeline.R","core-pipeline","alerttools_result methods expose a stable result contract",12,0,FALSE,FALSE,0,0.0209999999999999,0.002,0.0229999999999999,12
+"test-core-pipeline.R","core-pipeline","alerttools_result constructor handles empty and invalid inputs",5,0,FALSE,FALSE,0,0.00900000000000012,0.001,0.0089999999999999,5
+"test-core-pipeline.R","core-pipeline","incidence is a pure validated calculation",4,0,FALSE,FALSE,0,0.00599999999999978,0.001,0.006,4
+"test-core-pipeline.R","core-pipeline","pure pipeline validates schemas, workers and nowcasting inputs",4,0,FALSE,FALSE,0,0.00800000000000001,0,0.00800000000000001,4
+"test-core-pipeline.R","core-pipeline","seed scoping does not mutate caller random state",2,0,FALSE,FALSE,0,0.002,0.001,0.002,2
+"test-core-pipeline.R","core-pipeline","portable worker controls are validated",5,0,FALSE,FALSE,0,14.768,0.708,15.509,5
+"test-core-pipeline.R","core-pipeline","computational entry points contain no database or file access",1,0,FALSE,FALSE,0,0.00300000000000011,0,0.00400000000000134,1
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0440000000000005,0.003,0.0459999999999994,6
+"test-pipeline-group-keys.R","pipeline-group-keys","municipality-disease mismatches identify the offending pair",2,0,FALSE,FALSE,0,0.00700000000000145,0.001,0.00799999999999912,2
+"test-pipeline-group-order.R","pipeline-group-order","multiple municipality-disease groups equal isolated calculations",2,0,FALSE,FALSE,0,0.0370000000000026,0.001,0.0389999999999979,2
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr32-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr32-final.csv
new file mode 100644
index 0000000..08ca2cb
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr32-final.csv
@@ -0,0 +1,23 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",14,0,FALSE,FALSE,0,0.055,0.003,0.0579999999999999,14
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.095,0.001,0.095,2
+"test-api.R","api","public computational entry validates canonical keys before joining",4,0,FALSE,FALSE,0,0.011,0,0.012,4
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.123,0.004,0.128,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.116,0.001,0.118,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.127,0.00199999999999999,0.13,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.0589999999999999,0.002,0.0599999999999998,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.00800000000000001,0.001,0.0089999999999999,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.0220000000000002,0.002,0.024,10
+"test-core-pipeline.R","core-pipeline","pure pipeline runs deterministically from in-memory fixtures",10,0,FALSE,FALSE,0,0.02,0.002,0.022,10
+"test-core-pipeline.R","core-pipeline","pipeline keeps diseases separate within the same municipality",15,0,FALSE,FALSE,0,0.0610000000000002,0.003,0.063,15
+"test-core-pipeline.R","core-pipeline","alerttools_result methods expose a stable result contract",12,0,FALSE,FALSE,0,0.0229999999999999,0.00299999999999999,0.0249999999999999,12
+"test-core-pipeline.R","core-pipeline","alerttools_result constructor handles empty and invalid inputs",5,0,FALSE,FALSE,0,0.0089999999999999,0,0.0089999999999999,5
+"test-core-pipeline.R","core-pipeline","incidence is a pure validated calculation",4,0,FALSE,FALSE,0,0.00500000000000012,0,0.006,4
+"test-core-pipeline.R","core-pipeline","pure pipeline validates schemas, workers and nowcasting inputs",4,0,FALSE,FALSE,0,0.00800000000000001,0.001,0.00800000000000001,4
+"test-core-pipeline.R","core-pipeline","seed scoping does not mutate caller random state",2,0,FALSE,FALSE,0,0.002,0,0.002,2
+"test-core-pipeline.R","core-pipeline","portable worker controls are validated",5,0,FALSE,FALSE,0,14.558,0.724,15.312,5
+"test-core-pipeline.R","core-pipeline","computational entry points contain no database or file access",1,0,FALSE,FALSE,0,0.00299999999999656,0,0.00399999999999778,1
+"test-legacy-disease-guard.R","legacy-disease-guard","legacy adapter rejects mixed or inconsistent disease results",3,0,FALSE,FALSE,0,0.0150000000000006,0,0.0160000000000018,3
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0429999999999993,0.003,0.0459999999999994,6
+"test-pipeline-group-keys.R","pipeline-group-keys","municipality-disease mismatches identify the offending pair",2,0,FALSE,FALSE,0,0.00700000000000145,0.001,0.00700000000000145,2
+"test-pipeline-group-order.R","pipeline-group-order","multiple municipality-disease groups equal isolated calculations",2,0,FALSE,FALSE,0,0.0330000000000013,0.001,0.0339999999999989,2
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr33-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr33-final.csv
new file mode 100644
index 0000000..348ab4a
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr33-final.csv
@@ -0,0 +1,22 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",14,0,FALSE,FALSE,0,0.056,0.004,0.0589999999999999,14
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.096,0.001,0.098,2
+"test-api.R","api","public computational entry validates canonical keys before joining",4,0,FALSE,FALSE,0,0.012,0.000999999999999994,0.012,4
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.125,0.004,0.13,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.117,0.002,0.121,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.132,0.003,0.134,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.0610000000000002,0.002,0.063,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.00599999999999978,0.001,0.00700000000000012,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.022,0.002,0.024,10
+"test-core-pipeline.R","core-pipeline","pure pipeline runs deterministically from in-memory fixtures",10,0,FALSE,FALSE,0,0.018,0.002,0.0189999999999999,10
+"test-core-pipeline.R","core-pipeline","pipeline keeps diseases separate within the same municipality",15,0,FALSE,FALSE,0,0.0599999999999998,0.00299999999999999,0.063,15
+"test-core-pipeline.R","core-pipeline","alerttools_result methods expose a stable result contract",12,0,FALSE,FALSE,0,0.0210000000000001,0.003,0.024,12
+"test-core-pipeline.R","core-pipeline","alerttools_result constructor handles empty and invalid inputs",5,0,FALSE,FALSE,0,0.0089999999999999,0.001,0.01,5
+"test-core-pipeline.R","core-pipeline","incidence is a pure validated calculation",4,0,FALSE,FALSE,0,0.006,0,0.006,4
+"test-core-pipeline.R","core-pipeline","pure pipeline validates schemas, workers and nowcasting inputs",4,0,FALSE,FALSE,0,0.00800000000000001,0.001,0.00900000000000012,4
+"test-core-pipeline.R","core-pipeline","seed scoping does not mutate caller random state",2,0,FALSE,FALSE,0,0.00099999999999989,0,0.002,2
+"test-core-pipeline.R","core-pipeline","portable worker controls are validated",5,0,FALSE,FALSE,0,14.753,0.722,15.508,5
+"test-core-pipeline.R","core-pipeline","computational entry points contain no database or file access",1,0,FALSE,FALSE,0,0.00300000000000011,0.001,0.00399999999999778,1
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0450000000000017,0.002,0.0480000000000018,6
+"test-zika-transition.R","zika-transition","modern Zika lookup reports complete, partial and absent coverage",7,0,FALSE,FALSE,0,0.0519999999999996,0.002,0.0549999999999997,7
+"test-zika-transition.R","zika-transition","legacy Zika fallback preserves dengue rules and Zika result identity",6,0,FALSE,FALSE,0,0.0730000000000004,0.002,0.0749999999999993,6
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr34-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr34-final.csv
new file mode 100644
index 0000000..4251edb
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr34-final.csv
@@ -0,0 +1,29 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",14,0,FALSE,FALSE,0,0.055,0.003,0.0579999999999999,14
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.1,0.000999999999999994,0.101,2
+"test-api.R","api","public computational entry validates canonical keys before joining",4,0,FALSE,FALSE,0,0.011,0,0.012,4
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.122,0.004,0.126,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.118,0.00199999999999999,0.12,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.127,0.002,0.13,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.0619999999999998,0.002,0.063,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.00600000000000023,0.001,0.0069999999999999,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.024,0.001,0.0249999999999999,10
+"test-concurrency.R","concurrency","municipal processes and INLA threads are independently propagated",4,0,FALSE,FALSE,0,0.01,0.001,0.0109999999999999,4
+"test-concurrency.R","concurrency","serial and parallel pipelines preserve epidemiological output",7,0,FALSE,FALSE,0,0.024,0.024,0.071,7
+"test-concurrency.R","concurrency","INLA fitting and posterior sampling respect explicit thread budgets",6,0,FALSE,FALSE,0,0.432,0.024,0.458,6
+"test-concurrency.R","concurrency","INLA fitting failures preserve the operational diagnosis",1,0,FALSE,FALSE,0,0.00300000000000011,0,0.00300000000000011,1
+"test-concurrency.R","concurrency","parallel workers propagate failures instead of returning partial output",2,0,FALSE,FALSE,0,0.004,0.014,0.0190000000000001,2
+"test-core-pipeline.R","core-pipeline","pure pipeline runs deterministically from in-memory fixtures",10,0,FALSE,FALSE,0,0.0230000000000001,0.00800000000000001,0.0310000000000001,10
+"test-core-pipeline.R","core-pipeline","pipeline keeps diseases separate within the same municipality",15,0,FALSE,FALSE,0,0.0569999999999999,0.00599999999999998,0.0640000000000001,15
+"test-core-pipeline.R","core-pipeline","alerttools_result methods expose a stable result contract",12,0,FALSE,FALSE,0,0.0230000000000001,0.003,0.0259999999999998,12
+"test-core-pipeline.R","core-pipeline","alerttools_result constructor handles empty and invalid inputs",5,0,FALSE,FALSE,0,0.0069999999999999,0,0.00700000000000012,5
+"test-core-pipeline.R","core-pipeline","incidence is a pure validated calculation",4,0,FALSE,FALSE,0,0.006,0,0.00600000000000023,4
+"test-core-pipeline.R","core-pipeline","pure pipeline validates schemas, workers and nowcasting inputs",4,0,FALSE,FALSE,0,0.00800000000000001,0.001,0.00800000000000001,4
+"test-core-pipeline.R","core-pipeline","seed scoping does not mutate caller random state",2,0,FALSE,FALSE,0,0.00099999999999989,0,0.00099999999999989,2
+"test-core-pipeline.R","core-pipeline","portable worker controls are validated",5,0,FALSE,FALSE,0,14.642,0.762,15.437,5
+"test-core-pipeline.R","core-pipeline","computational entry points contain no database or file access",1,0,FALSE,FALSE,0,0.00300000000000011,0,0.00399999999999778,1
+"test-deprecation-policy.R","deprecation-policy","legacy warnings start at 1.3.0 and execute the lifecycle emitter",4,0,FALSE,FALSE,0,0.0180000000000007,0.001,0.0190000000000019,4
+"test-legacy-disease-guard.R","legacy-disease-guard","legacy adapter rejects mixed or inconsistent disease results",3,0,FALSE,FALSE,0,0.0210000000000008,0.001,0.0229999999999997,3
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0370000000000026,0.001,0.0380000000000003,6
+"test-pipeline-group-keys.R","pipeline-group-keys","municipality-disease mismatches identify the offending pair",2,0,FALSE,FALSE,0,0.00700000000000145,0,0.00799999999999912,2
+"test-pipeline-group-order.R","pipeline-group-order","multiple municipality-disease groups equal isolated calculations",2,0,FALSE,FALSE,0,0.0350000000000001,0.001,0.0360000000000014,2
diff --git a/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr36-final.csv b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr36-final.csv
new file mode 100644
index 0000000..88df91d
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/local-pr-checks/alerttools-review-local-pr36-final.csv
@@ -0,0 +1,73 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-alert-rules.R","alert-rules","setCriteria validates inputs and returns the legacy structure",5,0,FALSE,FALSE,0,0.037,0.002,0.0389999999999999,5
+"test-alert-rules.R","alert-rules","setCriteria keeps its legacy delay-list default",2,0,FALSE,FALSE,0,0.004,0.001,0.005,2
+"test-alert-rules.R","alert-rules","alert rules preserve output structure and delayed levels",6,0,FALSE,FALSE,0,0.016,0.000999999999999994,0.017,6
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",14,0,FALSE,FALSE,0,0.042,0.003,0.045,14
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.0760000000000001,0.001,0.077,2
+"test-api.R","api","public computational entry validates canonical keys before joining",4,0,FALSE,FALSE,0,0.0129999999999999,0,0.0129999999999999,4
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.122,0.005,0.127,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.117,0.002,0.119,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.131,0.002,0.134,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.0610000000000002,0.003,0.0640000000000001,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.00599999999999978,0.001,0.0069999999999999,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.022,0.001,0.0229999999999999,10
+"test-concurrency.R","concurrency","municipal processes and INLA threads are independently propagated",4,0,FALSE,FALSE,0,0.012,0.001,0.014,4
+"test-concurrency.R","concurrency","serial and parallel pipelines preserve epidemiological output",7,0,FALSE,FALSE,0,0.02,0.02,0.054,7
+"test-concurrency.R","concurrency","INLA fitting and posterior sampling respect explicit thread budgets",6,0,FALSE,FALSE,0,0.437,0.026,0.464,6
+"test-concurrency.R","concurrency","INLA fitting failures preserve the operational diagnosis",1,0,FALSE,FALSE,0,0.00299999999999989,0,0.00300000000000011,1
+"test-concurrency.R","concurrency","parallel workers propagate failures instead of returning partial output",2,0,FALSE,FALSE,0,0.004,0.014,0.0179999999999998,2
+"test-core-pipeline.R","core-pipeline","pure pipeline runs deterministically from in-memory fixtures",10,0,FALSE,FALSE,0,0.018,0.005,0.0230000000000001,10
+"test-core-pipeline.R","core-pipeline","pipeline keeps diseases separate within the same municipality",15,0,FALSE,FALSE,0,0.062,0.00999999999999998,0.0710000000000002,15
+"test-core-pipeline.R","core-pipeline","alerttools_result methods expose a stable result contract",12,0,FALSE,FALSE,0,0.024,0.003,0.0270000000000001,12
+"test-core-pipeline.R","core-pipeline","alerttools_result constructor handles empty and invalid inputs",5,0,FALSE,FALSE,0,0.00599999999999978,0.001,0.00700000000000012,5
+"test-core-pipeline.R","core-pipeline","incidence is a pure validated calculation",4,0,FALSE,FALSE,0,0.00499999999999989,0,0.00599999999999978,4
+"test-core-pipeline.R","core-pipeline","pure pipeline validates schemas, workers and nowcasting inputs",4,0,FALSE,FALSE,0,0.00800000000000001,0.001,0.00800000000000001,4
+"test-core-pipeline.R","core-pipeline","seed scoping does not mutate caller random state",2,0,FALSE,FALSE,0,0.00099999999999989,0,0.00200000000000022,2
+"test-core-pipeline.R","core-pipeline","portable worker controls are validated",5,0,FALSE,FALSE,0,14.804,0.797,15.633,5
+"test-core-pipeline.R","core-pipeline","computational entry points contain no database or file access",1,0,FALSE,FALSE,0,0.00400000000000134,0,0.00400000000000134,1
+"test-data-repository.R","data-repository","repository-backed readers expose stable domain schemas",8,0,FALSE,FALSE,0,0.0350000000000001,0.002,0.0380000000000003,8
+"test-data-repository.R","data-repository","bound values prevent SQL injection through repository filters",3,0,FALSE,FALSE,0,0.032,0.001,0.0330000000000013,3
+"test-data-repository.R","data-repository","case-record readers share date and disease normalization",7,0,FALSE,FALSE,0,0.0309999999999988,0.002,0.0329999999999977,7
+"test-data-repository.R","data-repository","climate and tweet repositories filter dates and preserve ordering",6,0,FALSE,FALSE,0,0.0530000000000008,0.002,0.0549999999999997,6
+"test-data-repository.R","data-repository","parameter writes implement explicit conflict policies",4,0,FALSE,FALSE,0,0.0459999999999994,0.002,0.046999999999997,4
+"test-data-repository.R","data-repository","batch write rolls back every row after a conflict",3,0,FALSE,FALSE,0,0.032,0.001,0.0330000000000013,3
+"test-data-repository.R","data-repository","station association updates are batched and transactional",3,0,FALSE,FALSE,0,0.0279999999999987,0.001,0.0289999999999999,3
+"test-data-repository.R","data-repository","alert history writes are batched, idempotent and conflict-aware",6,0,FALSE,FALSE,0,0.0489999999999995,0.002,0.0500000000000007,6
+"test-data-repository.R","data-repository","SQL file export quotes literals instead of interpolating user values",3,0,FALSE,FALSE,0,0.00600000000000023,0,0.00700000000000145,3
+"test-data-repository.R","data-repository","database functions require an explicit connection",2,0,FALSE,FALSE,0,0.027000000000001,0,0.027000000000001,2
+"test-deprecation-policy.R","deprecation-policy","legacy warnings start at 1.3.0 and execute the lifecycle emitter",4,0,FALSE,FALSE,0,0.0180000000000007,0.001,0.0190000000000019,4
+"test-documentation-examples.R","documentation-examples","published in-memory example runs in a clean environment",4,0,FALSE,FALSE,0,0.00800000000000267,0.001,0.00900000000000034,4
+"test-documentation-examples.R","documentation-examples","published SQLite example runs without credentials or production",4,0,FALSE,FALSE,0,0.0360000000000014,0.001,0.036999999999999,4
+"test-epidemiological-equivalence.R","epidemiological-equivalence","reference integrity is portable across text line endings",2,0,FALSE,FALSE,0,0.004999999999999,0.002,0.004999999999999,2
+"test-epidemiological-equivalence.R","epidemiological-equivalence","approved dependency and candidate preserve epidemiological outputs",8,0,FALSE,FALSE,0,0.169999999999998,0.00800000000000001,0.178999999999998,8
+"test-epidemiological-equivalence.R","epidemiological-equivalence","comparison fails on numerical, missingness and identity changes",2,0,FALSE,FALSE,0,0.00400000000000134,0,0.00400000000000134,2
+"test-epiweek.R","epiweek","calendar behavior is preserved across epidemiological year boundary",5,0,FALSE,FALSE,0,0.0069999999999979,0.001,0.00800000000000267,5
+"test-epiweek.R","epiweek","epidemiological calendar functions preserve types and boundaries",15,0,FALSE,FALSE,0,0.0150000000000006,0.003,0.0179999999999971,15
+"test-epiweek.R","epiweek","date conversion results retain their tabular contract",10,0,FALSE,FALSE,0,0.0109999999999992,0.002,0.0130000000000017,10
+"test-epiweek.R","epiweek","algorithmic calendar is equivalent to the legacy SE table",5,0,FALSE,FALSE,0,0.0229999999999997,0.002,0.0239999999999974,5
+"test-epiweek.R","epiweek","algorithmic calendar has no fixed annual boundary",5,0,FALSE,FALSE,0,0.321000000000002,0.005,0.327000000000002,5
+"test-epiweek.R","epiweek","epidemiological week validation rejects impossible values",5,0,FALSE,FALSE,0,0.00700000000000145,0,0.00700000000000145,5
+"test-epiweek.R","epiweek","SE 201815 and its neighbors have consistent bundled boundaries",10,0,FALSE,FALSE,0,0.230999999999998,0.004,0.235000000000003,10
+"test-fetch-cases.R","fetch-cases","getCases has a deterministic SQLite integration contract",13,0,FALSE,FALSE,0,0.0399999999999991,0.00299999999999989,0.0429999999999993,13
+"test-fetch-cases.R","fetch-cases","getCases reproduces its contract on ephemeral PostgreSQL",1,0,TRUE,FALSE,0,0,0.00100000000000011,0.00100000000000122,0
+"test-fetch-cases.R","fetch-cases","getCases rejects invalid user input before querying",3,0,FALSE,FALSE,0,0.0300000000000011,0.00099999999999989,0.0309999999999988,3
+"test-fixture-contracts.R","fixture-contracts","synthetic fixtures preserve tabular schemas and keys",10,0,FALSE,FALSE,0,0.00800000000000267,0.002,0.0110000000000028,10
+"test-inla-integration.R","inla-integration","real INLA preserves repeated and municipal-parallel results",1,0,TRUE,FALSE,0,0.00100000000000122,0,0.00100000000000122,0
+"test-inla-integration.R","inla-integration","terminated municipal workers cannot be mistaken for complete output",1,0,TRUE,FALSE,0,0.00399999999999778,0,0.00399999999999778,0
+"test-inla-reference.R","inla-reference","real INLA agrees with pinned calculations at the historical fitting budget",1,0,TRUE,FALSE,0,0.00100000000000122,0,0.00100000000000122,0
+"test-legacy-disease-guard.R","legacy-disease-guard","legacy adapter rejects mixed or inconsistent disease results",3,0,FALSE,FALSE,0,0.0100000000000016,0,0.00900000000000034,3
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0380000000000003,0.002,0.0399999999999991,6
+"test-optional-models.R","optional-models","MEM integration is available when its optional dependency is installed",2,0,FALSE,FALSE,0,0.0150000000000006,0.00300000000000011,0.0210000000000008,2
+"test-optional-models.R","optional-models","INLA integration is available when its optional dependency is installed",2,0,FALSE,FALSE,0,0.00199999999999889,0.00099999999999989,0.00300000000000011,2
+"test-pipe-infodengue-firstday.R","pipe-infodengue-firstday","pipe_infodengue preserves firstday defaults and historical overrides",14,0,FALSE,FALSE,0,0.0410000000000004,0.00300000000000011,0.0440000000000005,14
+"test-pipeline-group-keys.R","pipeline-group-keys","municipality-disease mismatches identify the offending pair",2,0,FALSE,FALSE,0,0.00799999999999912,0,0.00800000000000267,2
+"test-pipeline-group-order.R","pipeline-group-order","multiple municipality-disease groups equal isolated calculations",2,0,FALSE,FALSE,0,0.0329999999999977,0.00100000000000011,0.0339999999999989,2
+"test-remove-tweet-historical-alerts.R","remove-tweet-historical-alerts","tabela_historico excludes legacy tweet input",3,0,FALSE,FALSE,0,0.0109999999999992,0.00100000000000011,0.0120000000000005,3
+"test-remove-tweet-historical-alerts.R","remove-tweet-historical-alerts","write_alerta SQL omits tweet for every disease table",12,0,FALSE,FALSE,0,0.0210000000000008,0.00099999999999989,0.022000000000002,12
+"test-rt.R","rt","Rt numerical regression baseline is preserved",8,0,FALSE,FALSE,0,0.00700000000000145,0.002,0.00899999999999679,8
+"test-utilities.R","utilities","municipal geocode conversion preserves regular and exceptional cases",6,0,FALSE,FALSE,0,0.004999999999999,0.00099999999999989,0.00600000000000023,6
+"test-utilities.R","utilities","missing values are filled by the selected deterministic rule",2,0,FALSE,FALSE,0,0.00199999999999889,0.00100000000000011,0.00300000000000011,2
+"test-utilities.R","utilities","temperature extrapolation preserves length and removes tail gaps",3,0,FALSE,FALSE,0,0.0500000000000007,0.002,0.0519999999999996,3
+"test-utilities.R","utilities","database functions validate absent connections and malformed input",9,0,FALSE,FALSE,0,0.0229999999999997,0.00099999999999989,0.0229999999999997,9
+"test-zika-transition.R","zika-transition","modern Zika lookup reports complete, partial and absent coverage",7,0,FALSE,FALSE,0,0.0520000000000032,0.002,0.0530000000000008,7
+"test-zika-transition.R","zika-transition","legacy Zika fallback preserves dengue rules and Zika result identity",6,0,FALSE,FALSE,0,0.0740000000000016,0.002,0.075999999999997,6
diff --git a/docs/refactoring/evidence/review-2026-10-29/postgres/candidate-sources.csv b/docs/refactoring/evidence/review-2026-10-29/postgres/candidate-sources.csv
new file mode 100644
index 0000000..27b1049
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/postgres/candidate-sources.csv
@@ -0,0 +1,16 @@
+"file","md5"
+"R/adjust_incidence_functions.R","ace1a8f7edefeb4f30cf9b270bd54a6e"
+"R/alert_functions.R","ee0e0f4af1e1ddfcb3b5bc22aee308bd"
+"R/AlertTools.R","914a6e16ea0a0082ce67a633412be6db"
+"R/api.R","8278aeb8597c696f643534a404e6efcd"
+"R/auxfun_for_Rt.R","8891b161e29b050a5cc3a5195d57fdc8"
+"R/core_pipeline.R","7166c9ad0da9d4e4d59d0ade8ff640ee"
+"R/data_repository.R","a4d0d7caffb3a498c46107cb6aa0b64c"
+"R/data.R","59f06e0b4bcdc661c36257c2e76bc053"
+"R/dengue-mem.R","c3011ac10b0c40e288db8e8fac2d996b"
+"R/epiweek.R","f7f1a39d433ee2240e193a8e6948bf9b"
+"R/get_timeseries.R","1959852ae906cf506b97b64c5eec2712"
+"R/infodengue_apply_mem.R","47f753f023c0fdd6670741fe6db8a722"
+"R/nowcasting_fun.R","c60affcefca4e054ea63e00595cb0712"
+"R/Rt_functions.R","66e74eba008a95aa92c834671707ebf3"
+"R/utility_tools.R","25a0b36f3b3eeeca089e602f809c2844"
diff --git a/docs/refactoring/evidence/review-2026-10-29/postgres/environment.txt b/docs/refactoring/evidence/review-2026-10-29/postgres/environment.txt
new file mode 100644
index 0000000..6c53c65
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/postgres/environment.txt
@@ -0,0 +1,42 @@
+R version 4.4.3 (2025-02-28)
+Platform: aarch64-apple-darwin20
+Running under: macOS 26.6.2
+
+Matrix products: default
+BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib
+LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
+
+locale:
+[1] C.UTF-8/C.UTF-8/C.UTF-8/C/C.UTF-8/C.UTF-8
+
+time zone: America/Maceio
+tzcode source: internal
+
+attached base packages:
+[1] stats graphics grDevices utils datasets methods base
+
+other attached packages:
+[1] AlertTools_1.2.0 testthat_3.3.2
+
+loaded via a namespace (and not attached):
+ [1] gtable_0.3.6 ggplot2_4.0.2 devtools_2.5.0 RcppRoll_0.3.1
+ [5] lattice_0.22-9 vctrs_0.7.2 tools_4.4.3 generics_0.1.4
+ [9] parallel_4.4.3 proxy_0.4-29 tibble_3.3.1 RSQLite_2.4.6
+[13] blob_1.3.0 pkgconfig_2.0.3 KernSmooth_2.23-26 Matrix_1.7-5
+[17] RColorBrewer_1.1-3 S7_0.2.1 desc_1.4.3 assertthat_0.2.1
+[21] lifecycle_1.0.5 compiler_4.4.3 farver_2.1.2 stringr_1.6.0
+[25] fmesher_0.7.0 brio_1.1.5 class_7.3-23 usethis_3.2.1
+[29] pillar_1.11.1 tidyr_1.3.2 ellipsis_0.3.2 classInt_0.4-11
+[33] cachem_1.1.0 RPostgres_1.4.10 sessioninfo_1.2.3 mclust_6.1.2
+[37] boot_1.3-32 nlme_3.1-168 fracdiff_1.5-3 tidyselect_1.2.1
+[41] stringi_1.8.7 sf_1.1-0 dplyr_1.2.0 purrr_1.2.1
+[45] splines_4.4.3 rprojroot_2.1.1 fastmap_1.2.0 grid_4.4.3
+[49] colorspace_2.1-2 cli_3.6.5 magrittr_2.0.4 pkgbuild_1.4.8
+[53] sm_2.2-6.0 e1071_1.7-17 withr_3.0.2 waldo_0.6.2
+[57] scales_1.4.0 bit64_4.6.0-1 forecast_9.0.2 lubridate_1.9.5
+[61] timechange_0.4.0 bit_4.6.0 otel_0.2.0 timeDate_4052.112
+[65] zoo_1.8-15 hms_1.1.4 urca_1.3-4 memoise_2.0.1
+[69] EnvStats_3.1.0 mem_2.19 rlang_1.1.7 Rcpp_1.1.1
+[73] glue_1.8.0 INLA_24.12.11 DBI_1.3.0 pkgload_1.5.0
+[77] rstudioapi_0.18.0 R6_2.6.1 plyr_1.8.9 units_1.0-1
+[81] fs_1.6.7
diff --git a/docs/refactoring/evidence/review-2026-10-29/postgres/test-results.csv b/docs/refactoring/evidence/review-2026-10-29/postgres/test-results.csv
new file mode 100644
index 0000000..d64a116
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/postgres/test-results.csv
@@ -0,0 +1,77 @@
+"file","context","test","nb","failed","skipped","error","warning","user","system","real","passed"
+"test-alert-rules.R","alert-rules","setCriteria validates inputs and returns the legacy structure",5,0,FALSE,FALSE,0,0.0379999999999999,0.002,0.04,5
+"test-alert-rules.R","alert-rules","setCriteria keeps its legacy delay-list default",2,0,FALSE,FALSE,0,0.004,0.001,0.005,2
+"test-alert-rules.R","alert-rules","alert rules preserve output structure and delayed levels",6,0,FALSE,FALSE,0,0.015,0.001,0.018,6
+"test-api.R","api","new_alert_inputs validates, normalizes, and orders public schemas",14,0,FALSE,FALSE,0,0.042,0.003,0.0449999999999999,14
+"test-api.R","api","run_alert_pipeline is equivalent to the approved pure pipeline",2,0,FALSE,FALSE,0,0.079,0.001,0.081,2
+"test-api.R","api","public computational entry validates canonical keys before joining",4,0,FALSE,FALSE,0,0.0119999999999999,0.001,0.014,4
+"test-api.R","api","database API fetches a complete, explicitly bounded input bundle",9,0,FALSE,FALSE,0,0.114,0.006,0.125,9
+"test-api.R","api","new persistence API writes results and parameters explicitly",5,0,FALSE,FALSE,0,0.123,0.002,0.127,5
+"test-api.R","api","legacy wrappers preserve adapters without warning before 1.3.0",10,0,FALSE,FALSE,0,0.114,0.00299999999999999,0.118,10
+"test-api.R","api","legacy pipeline and history wrappers preserve their public contracts",8,0,FALSE,FALSE,0,0.0640000000000001,0.002,0.0670000000000002,8
+"test-api.R","api","snake_case computational aliases preserve baseline results",3,0,FALSE,FALSE,0,0.00700000000000012,0.002,0.00700000000000012,3
+"test-api.R","api","legacy computational wrappers remain equivalent without early warnings",10,0,FALSE,FALSE,0,0.024,0.002,0.0249999999999999,10
+"test-concurrency.R","concurrency","municipal processes and INLA threads are independently propagated",4,0,FALSE,FALSE,0,0.0150000000000001,0.002,0.016,4
+"test-concurrency.R","concurrency","serial and parallel pipelines preserve epidemiological output",7,0,FALSE,FALSE,0,0.0229999999999999,0.024,0.06,7
+"test-concurrency.R","concurrency","INLA fitting and posterior sampling respect explicit thread budgets",6,0,FALSE,FALSE,0,0.486,0.028,0.518,6
+"test-concurrency.R","concurrency","INLA fitting failures preserve the operational diagnosis",1,0,FALSE,FALSE,0,0.00299999999999989,0,0.004,1
+"test-concurrency.R","concurrency","parallel workers propagate failures instead of returning partial output",2,0,FALSE,FALSE,0,0.004,0.015,0.02,2
+"test-consumer-integration.R","consumer-integration","pinned consumer preserves state, recovery and artifacts on SQLite",29,0,FALSE,FALSE,0,2.492,0.066,2.567,29
+"test-consumer-integration.R","consumer-integration","pinned consumer replays reference and candidate SQL on PostgreSQL",39,0,FALSE,FALSE,0,2.452,0.059,2.763,39
+"test-consumer-integration.R","consumer-integration","SQL export retains numeric precision instead of formatting a character matrix",1,0,FALSE,FALSE,0,0.0270000000000001,0.002,0.0300000000000002,1
+"test-core-pipeline.R","core-pipeline","pure pipeline runs deterministically from in-memory fixtures",10,0,FALSE,FALSE,0,0.0180000000000007,0.003,0.0200000000000005,10
+"test-core-pipeline.R","core-pipeline","pipeline keeps diseases separate within the same municipality",15,0,FALSE,FALSE,0,0.0609999999999999,0.003,0.0640000000000001,15
+"test-core-pipeline.R","core-pipeline","alerttools_result methods expose a stable result contract",12,0,FALSE,FALSE,0,0.0219999999999994,0.003,0.024,12
+"test-core-pipeline.R","core-pipeline","alerttools_result constructor handles empty and invalid inputs",5,0,FALSE,FALSE,0,0.00700000000000056,0.000999999999999945,0.00699999999999967,5
+"test-core-pipeline.R","core-pipeline","incidence is a pure validated calculation",4,0,FALSE,FALSE,0,0.00600000000000023,0.001,0.00699999999999967,4
+"test-core-pipeline.R","core-pipeline","pure pipeline validates schemas, workers and nowcasting inputs",4,0,FALSE,FALSE,0,0.00900000000000034,0,0.00900000000000034,4
+"test-core-pipeline.R","core-pipeline","seed scoping does not mutate caller random state",2,0,FALSE,FALSE,0,0.00199999999999978,0.001,0.00200000000000067,2
+"test-core-pipeline.R","core-pipeline","portable worker controls are validated",5,0,FALSE,FALSE,0,15.387,0.855,16.301,5
+"test-core-pipeline.R","core-pipeline","computational entry points contain no database or file access",1,0,FALSE,FALSE,0,0.00300000000000011,0,0.00400000000000134,1
+"test-data-repository.R","data-repository","repository-backed readers expose stable domain schemas",8,0,FALSE,FALSE,0,0.036999999999999,0.00299999999999989,0.0399999999999991,8
+"test-data-repository.R","data-repository","bound values prevent SQL injection through repository filters",3,0,FALSE,FALSE,0,0.0280000000000022,0.00100000000000011,0.0299999999999976,3
+"test-data-repository.R","data-repository","case-record readers share date and disease normalization",7,0,FALSE,FALSE,0,0.0359999999999978,0.002,0.0390000000000015,7
+"test-data-repository.R","data-repository","climate and tweet repositories filter dates and preserve ordering",6,0,FALSE,FALSE,0,0.0510000000000019,0.002,0.0530000000000008,6
+"test-data-repository.R","data-repository","parameter writes implement explicit conflict policies",4,0,FALSE,FALSE,0,0.0489999999999995,0.00100000000000011,0.0500000000000007,4
+"test-data-repository.R","data-repository","batch write rolls back every row after a conflict",3,0,FALSE,FALSE,0,0.032,0.00100000000000011,0.032,3
+"test-data-repository.R","data-repository","station association updates are batched and transactional",3,0,FALSE,FALSE,0,0.0309999999999988,0.00099999999999989,0.032,3
+"test-data-repository.R","data-repository","alert history writes are batched, idempotent and conflict-aware",6,0,FALSE,FALSE,0,0.0500000000000007,0.002,0.0519999999999996,6
+"test-data-repository.R","data-repository","SQL file export quotes literals instead of interpolating user values",3,0,FALSE,FALSE,0,0.004999999999999,0.00100000000000011,0.00600000000000023,3
+"test-data-repository.R","data-repository","database functions require an explicit connection",2,0,FALSE,FALSE,0,0.0240000000000009,0.00099999999999989,0.0250000000000021,2
+"test-deprecation-policy.R","deprecation-policy","legacy warnings start at 1.3.0 and execute the lifecycle emitter",4,0,FALSE,FALSE,0,0.0160000000000018,0.00100000000000011,0.0169999999999995,4
+"test-documentation-examples.R","documentation-examples","published in-memory example runs in a clean environment",4,0,FALSE,FALSE,0,0.00799999999999912,0.00099999999999989,0.00899999999999679,4
+"test-documentation-examples.R","documentation-examples","published SQLite example runs without credentials or production",4,0,FALSE,FALSE,0,0.0390000000000015,0.00100000000000011,0.0399999999999991,4
+"test-epidemiological-equivalence.R","epidemiological-equivalence","reference integrity is portable across text line endings",2,0,FALSE,FALSE,0,0.00199999999999889,0.00100000000000011,0.00399999999999778,2
+"test-epidemiological-equivalence.R","epidemiological-equivalence","approved dependency and candidate preserve epidemiological outputs",8,0,FALSE,FALSE,0,0.140000000000001,0.00800000000000001,0.149000000000001,8
+"test-epidemiological-equivalence.R","epidemiological-equivalence","comparison fails on numerical, missingness and identity changes",4,0,FALSE,FALSE,0,0.00900000000000034,0,0.00900000000000034,4
+"test-epiweek.R","epiweek","calendar behavior is preserved across epidemiological year boundary",5,0,FALSE,FALSE,0,0.00600000000000023,0.00099999999999989,0.00799999999999912,5
+"test-epiweek.R","epiweek","epidemiological calendar functions preserve types and boundaries",15,0,FALSE,FALSE,0,0.0150000000000006,0.00300000000000011,0.0180000000000007,15
+"test-epiweek.R","epiweek","date conversion results retain their tabular contract",10,0,FALSE,FALSE,0,0.00900000000000034,0.002,0.0100000000000016,10
+"test-epiweek.R","epiweek","algorithmic calendar is equivalent to the legacy SE table",5,0,FALSE,FALSE,0,0.0240000000000009,0.00099999999999989,0.0250000000000021,5
+"test-epiweek.R","epiweek","algorithmic calendar has no fixed annual boundary",5,0,FALSE,FALSE,0,0.328999999999997,0.006,0.336000000000002,5
+"test-epiweek.R","epiweek","epidemiological week validation rejects impossible values",5,0,FALSE,FALSE,0,0.00700000000000145,0.00099999999999989,0.00800000000000267,5
+"test-epiweek.R","epiweek","SE 201815 and its neighbors have consistent bundled boundaries",10,0,FALSE,FALSE,0,0.230999999999998,0.004,0.234999999999999,10
+"test-fetch-cases.R","fetch-cases","getCases has a deterministic SQLite integration contract",13,0,FALSE,FALSE,0,0.0449999999999982,0.00300000000000011,0.0479999999999983,13
+"test-fetch-cases.R","fetch-cases","getCases reproduces its contract on ephemeral PostgreSQL",10,0,FALSE,FALSE,0,0.0470000000000006,0.00499999999999989,0.0779999999999994,10
+"test-fetch-cases.R","fetch-cases","getCases rejects invalid user input before querying",3,0,FALSE,FALSE,0,0.0359999999999978,0.00100000000000011,0.036999999999999,3
+"test-fixture-contracts.R","fixture-contracts","synthetic fixtures preserve tabular schemas and keys",10,0,FALSE,FALSE,0,0.00799999999999912,0.002,0.00999999999999801,10
+"test-inla-consumer.R","inla-consumer","real Bayesian consumer fallback isolates failures and preserves artifacts",1,0,TRUE,FALSE,0,0.00100000000000122,0.00100000000000011,0.00100000000000122,0
+"test-inla-integration.R","inla-integration","real INLA preserves repeated and municipal-parallel results",1,0,TRUE,FALSE,0,0.000999999999997669,0,0.00100000000000122,0
+"test-inla-integration.R","inla-integration","terminated municipal workers cannot be mistaken for complete output",1,0,TRUE,FALSE,0,0.00400000000000134,0.00099999999999989,0.00399999999999778,0
+"test-inla-reference.R","inla-reference","real INLA agrees with pinned calculations at the historical fitting budget",1,0,TRUE,FALSE,0,0.000999999999997669,0,0.000999999999997669,0
+"test-legacy-disease-guard.R","legacy-disease-guard","legacy adapter rejects mixed or inconsistent disease results",3,0,FALSE,FALSE,0,0.00999999999999801,0,0.00999999999999801,3
+"test-legacy-fallback.R","legacy-fallback","municipal fallback preserves distinct parameters without database reads",6,0,FALSE,FALSE,0,0.0440000000000005,0.002,0.0479999999999983,6
+"test-optional-models.R","optional-models","MEM integration is available when its optional dependency is installed",2,0,FALSE,FALSE,0,0.0189999999999984,0.004,0.0330000000000013,2
+"test-optional-models.R","optional-models","INLA integration is available when its optional dependency is installed",2,0,FALSE,FALSE,0,0.00199999999999889,0.00099999999999989,0.00200000000000244,2
+"test-pipe-infodengue-firstday.R","pipe-infodengue-firstday","pipe_infodengue preserves firstday defaults and historical overrides",14,0,FALSE,FALSE,0,0.0429999999999993,0.00299999999999989,0.0459999999999994,14
+"test-pipeline-group-keys.R","pipeline-group-keys","municipality-disease mismatches identify the offending pair",2,0,FALSE,FALSE,0,0.00799999999999912,0.00100000000000011,0.00799999999999912,2
+"test-pipeline-group-order.R","pipeline-group-order","multiple municipality-disease groups equal isolated calculations",2,0,FALSE,FALSE,0,0.0420000000000016,0.002,0.0429999999999993,2
+"test-remove-tweet-historical-alerts.R","remove-tweet-historical-alerts","tabela_historico excludes legacy tweet input",3,0,FALSE,FALSE,0,0.0109999999999992,0.00099999999999989,0.0120000000000005,3
+"test-remove-tweet-historical-alerts.R","remove-tweet-historical-alerts","write_alerta SQL omits tweet for every disease table",12,0,FALSE,FALSE,0,0.0169999999999995,0.002,0.0190000000000019,12
+"test-rt.R","rt","Rt numerical regression baseline is preserved",8,0,FALSE,FALSE,0,0.00799999999999912,0.002,0.0100000000000016,8
+"test-utilities.R","utilities","municipal geocode conversion preserves regular and exceptional cases",6,0,FALSE,FALSE,0,0.00600000000000023,0.00099999999999989,0.0069999999999979,6
+"test-utilities.R","utilities","missing values are filled by the selected deterministic rule",2,0,FALSE,FALSE,0,0.00600000000000023,0.00100000000000011,0.00600000000000023,2
+"test-utilities.R","utilities","temperature extrapolation preserves length and removes tail gaps",3,0,FALSE,FALSE,0,0.0500000000000007,0.002,0.0530000000000008,3
+"test-utilities.R","utilities","database functions validate absent connections and malformed input",9,0,FALSE,FALSE,0,0.0190000000000019,0.00099999999999989,0.0199999999999996,9
+"test-zika-transition.R","zika-transition","modern Zika lookup reports complete, partial and absent coverage",7,0,FALSE,FALSE,0,0.0549999999999997,0.00299999999999989,0.0589999999999975,7
+"test-zika-transition.R","zika-transition","legacy Zika fallback preserves dengue rules and Zika result identity",6,0,FALSE,FALSE,0,0.0769999999999982,0.00200000000000022,0.0800000000000018,6
diff --git a/docs/refactoring/evidence/review-2026-10-29/pr35-ast-check.txt b/docs/refactoring/evidence/review-2026-10-29/pr35-ast-check.txt
new file mode 100644
index 0000000..8d0d2cc
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/pr35-ast-check.txt
@@ -0,0 +1 @@
+All 15 R source ASTs are identical between PR34 and PR35; changes are documentation only.
diff --git a/docs/refactoring/evidence/review-2026-10-29/ready-refs.json b/docs/refactoring/evidence/review-2026-10-29/ready-refs.json
new file mode 100644
index 0000000..d80350f
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/ready-refs.json
@@ -0,0 +1,61 @@
+{
+ "note": "Preparation snapshot before the final evidence-only documentation commit on PR37. Validation-script EOF normalization was checked for identical R ASTs; numerical package sources are unchanged. Resolve the current local branch head and recheck the remote before publication. No branch was pushed.",
+ "consolidated_code_commit": "c587284477eeda5ddcbaa793b97e40bc35d4ab8b",
+ "branches": {
+ "28": {
+ "branch": "codex/review-ready/pr2-legacy-compat",
+ "remote_branch": "codex/pr2-legacy-compat",
+ "expected_remote_head_at_intake": "7213aa10fc9d8c2c2830406b183f4e4c99c55d10",
+ "validation_snapshot_sha": "3a7e7c8735bd3fb19560bfa79c9f2b216efac108"
+ },
+ "30": {
+ "branch": "codex/review-ready/pr4-deprecation-policy",
+ "remote_branch": "codex/pr4-deprecation-policy",
+ "expected_remote_head_at_intake": "0fd9c0da8f3d830d115f7034102f74038f63aefb",
+ "validation_snapshot_sha": "842005f170d008566b33e5729ee94c5fffcf8123"
+ },
+ "31": {
+ "branch": "codex/review-ready/pr5-canonical-inputs",
+ "remote_branch": "codex/pr5-canonical-inputs",
+ "expected_remote_head_at_intake": "c6fe5ccd7b7cb87aa8c114e97e57984655eb9bff",
+ "validation_snapshot_sha": "d4012a317d01464189c7c22a6c0cd37c5c717415"
+ },
+ "32": {
+ "branch": "codex/review-ready/pr6-municipality-disease",
+ "remote_branch": "codex/pr6-municipality-disease",
+ "expected_remote_head_at_intake": "3d62c689633af001ddb97884213b081f862a4768",
+ "validation_snapshot_sha": "b453e84bae944e3fe84269e29ae9abbd5e18c5f8"
+ },
+ "33": {
+ "branch": "codex/review-ready/pr7-zika-transition",
+ "remote_branch": "codex/pr7-zika-transition",
+ "expected_remote_head_at_intake": "88efaf004725d1bd031117f59edb5595f629d6a5",
+ "validation_snapshot_sha": "a8278ed1fc84ab8003b9953389f107996929cfaa"
+ },
+ "34": {
+ "branch": "codex/review-ready/pr8-concurrency-controls",
+ "remote_branch": "codex/pr8-concurrency-controls",
+ "expected_remote_head_at_intake": "e7de3e71b7e95e2c79cf6391565a4b760536ea63",
+ "validation_snapshot_sha": "ba72b474fbee3eecc9e45dfb9e08e361e95eb4f5"
+ },
+ "35": {
+ "branch": "codex/review-ready/pr9-minimum-history-contract",
+ "remote_branch": "codex/pr9-minimum-history-contract",
+ "expected_remote_head_at_intake": "2f5ad3e327d36aaea357318875051e2449a469c1",
+ "validation_snapshot_sha": "c6696b3a20e0e19aee16dbf529f49d770a0082c0"
+ },
+ "36": {
+ "branch": "codex/review-ready/pr10-epidemiological-equivalence",
+ "remote_branch": "codex/pr10-epidemiological-equivalence",
+ "expected_remote_head_at_intake": "1534d94ee7ff0d80fb8562eb46b6b1754f927f22",
+ "validation_snapshot_sha": "cdec43b1c11b3cb993cfcaa6440ced79f1077e6c"
+ },
+ "37": {
+ "branch": "codex/review-ready/pr11-consumer-integration",
+ "remote_branch": "codex/pr11-consumer-integration",
+ "expected_remote_head_at_intake": "15e091501e2ebbf7ea463c51c44a87964b2de724",
+ "validation_snapshot_sha": "d823bb294de7921ea69fdd5ea0495caeaae06005"
+ }
+ },
+ "remote_changes_during_implementation": {}
+}
diff --git a/docs/refactoring/evidence/review-2026-10-29/validation-eof-ast-proof.json b/docs/refactoring/evidence/review-2026-10-29/validation-eof-ast-proof.json
new file mode 100644
index 0000000..7ea7aca
--- /dev/null
+++ b/docs/refactoring/evidence/review-2026-10-29/validation-eof-ast-proof.json
@@ -0,0 +1,62 @@
+[
+ {
+ "file": "tests/reference/frame-comparison.R",
+ "before_blob": "a8bdbbb1372b0ad85fc76f988662f9f673b87631",
+ "after_blob": "9f0e19ad1a719c9fd531fea2a336f162f46972fd",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/reference/inla-reference-validation.R",
+ "before_blob": "4c9bd7cebbff8d3ec66ad04e11bcf0a3214188a9",
+ "after_blob": "e6a462ba6dab6aee5ec763641cf880b3145d1201",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/helper-inla.R",
+ "before_blob": "e27c9b834fdd19a46982f1dbeea6f6c29381ba56",
+ "after_blob": "1638f82f324606a8d4f47033881545e094292383",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/helper-review.R",
+ "before_blob": "2a688eae350f1fd5cd8ad43558f5386a06460fbb",
+ "after_blob": "d83da45bb0f87f3f0fe2396f6251db4f612f9a50",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/test-deprecation-policy.R",
+ "before_blob": "f7b77f3574df2b9872439876a106725dc0d43c95",
+ "after_blob": "1a88b6ea509106c49c7fb3402b3ad8829a1fc32c",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/test-inla-consumer.R",
+ "before_blob": "54a14d557b6779899f209c26993acc6600b81838",
+ "after_blob": "8638d6593191dee597dfd4dbefee2e9efc27c041",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/test-inla-reference.R",
+ "before_blob": "51c82b665c105cd3971dadc4bf29ab852373c310",
+ "after_blob": "9e020ddbf7e81b39942333e41053a4817ba0b685",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/test-legacy-disease-guard.R",
+ "before_blob": "b9052f3b4329f4d74fc1631bdb82a5e971a99f03",
+ "after_blob": "77cd0e8711a3b7e8ad559582e28bcd9fc93928f4",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/test-legacy-fallback.R",
+ "before_blob": "0d5fc21374d368809dd507987cf4596ba7de8429",
+ "after_blob": "3aabf667cf075ddc55b4103aed321ad06fb24ce3",
+ "ast_identical": true
+ },
+ {
+ "file": "tests/testthat/test-pipeline-group-keys.R",
+ "before_blob": "5cdabfcd31a74cbb7ef07cdcc20354de8f3dda35",
+ "after_blob": "74d470e978abf03bc9ce3f57466fe1174a98b151",
+ "ast_identical": true
+ }
+]
diff --git a/docs/refactoring/plano-correcao-reviews-2026-10-29.md b/docs/refactoring/plano-correcao-reviews-2026-10-29.md
new file mode 100644
index 0000000..eb8920e
--- /dev/null
+++ b/docs/refactoring/plano-correcao-reviews-2026-10-29.md
@@ -0,0 +1,466 @@
+# Plano executável de correção dos reviews e reorganização dos PRs
+
+Data: 29/10/2026. Repositório: AlertaDengue/AlertTools.
+
+Estado deste documento: **correções implementadas e validadas localmente; publicação não executada**.
+
+Relatório: [correcoes-review-2026-10-29.md](correcoes-review-2026-10-29.md).
+A auditoria Zika em homologação depende de acesso e da lista operacional, não encontrados no repositório.
+Este arquivo é a fonte de execução e de passagem de trabalho entre agentes.
+Os estados abaixo não certificam trabalho feito. Atualizá-los somente com evidências.
+
+## 1. Resultado esperado e limites
+
+Corrigir os comentários de Sandro nos PRs #28, #30, #31, #32 e #34;
+organizar a auditoria do #33; preservar as entregas aprovadas dos #35–37;
+reconstruir a cadeia de branches sem perder os merges de #27 e #29.
+
+Ao terminar, cada PR deve conter um diff próprio, testes proporcionais ao seu
+escopo, CI aprovado no commit publicado e uma resposta preparada para o review.
+Não criar PRs substitutos, mesclar PRs, publicar release, alterar o pin do
+consumidor ou escrever em banco operacional como parte deste plano.
+Postar respostas ou solicitar revisão apenas quando essa comunicação estiver
+autorizada; até lá, entregar os textos prontos no relatório de execução.
+
+Não mudar o algoritmo epidemiológico ou aumentar limites de concorrência para
+fazer a validação passar. Não regenerar valores esperados a partir da candidata.
+Falhas devem resultar em diagnóstico e correção ou pendência explicitamente registrada.
+
+## 2. Situação verificada e referências iniciais
+
+Estas referências são um retrato, não valores a serem impostos ao remoto.
+Revalidar no início da execução. Se o remoto mudou, incorporar a mudança e
+registrar os novos limites antes de qualquer rebase ou publicação.
+
+| PR | Branch | Base atual | Revisão inicial / observação |
+|---|---|---|---|
+| #20 | `codex/alerttools-1.2.0-rc1` | `master` | `57428ed`; contém o merge do #27 |
+| #27 | `codex/pr1-characterization-baseline` | candidata | Mesclado; merge `57428ed998032a5d958afeb55a372145cd0b8601` |
+| #28 | `codex/pr2-legacy-compat` | candidata | Remoto `7213aa10fc9d8c2c2830406b183f4e4c99c55d10`; já contém o merge do #29 |
+| #29 | `codex/pr3-setcriteria-compat` | PR #28 | Mesclado; commit original `e76044d` |
+| #30 | `codex/pr4-deprecation-policy` | PR #28 | `0fd9c0d` |
+| #31 | `codex/pr5-canonical-inputs` | PR #30 | `c6fe5cc` |
+| #32 | `codex/pr6-municipality-disease` | PR #31 | `3d62c68` |
+| #33 | `codex/pr7-zika-transition` | PR #32 | `88efaf0`; sem aprovação vigente no estado agregado |
+| #34 | `codex/pr8-concurrency-controls` | PR #33 | `e7de3e7` |
+| #35 | `codex/pr9-minimum-history-contract` | PR #34 | `2f5ad3e`; aprovado |
+| #36 | `codex/pr10-epidemiological-equivalence` | PR #35 | `1534d94`; aprovado |
+| #37 | `codex/pr11-consumer-integration` | PR #36 | `15e0915`; aprovado |
+
+`master` verificado: `e460b3b8c15ab28e8755f482d576cf7280803b34`.
+A branch local do #28 estava desatualizada e ainda apontava para `9931177`.
+**Não usar essa ponta local como origem de uma reconstrução que perca o #29.**
+
+Referências históricas imutáveis para comparação:
+
+- AlertTools usado pelo consumidor: `e460b3b8c15ab28e8755f482d576cf7280803b34`.
+- Consumidor AlertaDengueAnalise: `27a03f26a9bf366597ef135e7da8d2f620ea9a8e`.
+- Snapshots: `tests/reference/e460b3b8/` e
+ `tests/reference/consumer-27a03f26/`; preservar origem e integridade com texto LF/CRLF.
+
+## 3. Organização dos agentes e dependências
+
+Não operar duas branches no mesmo checkout simultaneamente. Se houver execução
+concorrente, usar checkouts isolados. Um único integrador controla a cadeia,
+rebases e publicação. Agentes especialistas entregam commits identificados;
+não fazem rebase ou push de branches pertencentes a outro agente.
+
+| ID | Responsável sugerido | Depende de | Entrega | Estado |
+|---|---|---|---|---|
+| R00 | Integrador | — | Inventário atualizado, backups e mapa de commits | Validado |
+| R01 | Agente de compatibilidade | R00 | Correção e teste mínimo no #28 | Validado |
+| R02 | Agente de API/documentação | R00; integração após R01 | Testes de versão e guia corrigido no #30 | Validado |
+| R03 | Agente de pipeline | R00; integração após R02 | Granularidade no #31 e proteção legada no #32 | Validado |
+| R04 | Agente de INLA | R00 para preparar; R03 para integração | Testes reais, runner e benchmark no #34 | Validado |
+| R05 | Agente de homologação | R00; candidata consolidada para executar | Auditoria Zika e relatório do #33 | Pendente de ambiente externo |
+| R06 | Integrador | R01–R04 | Cadeia reconstruída, #35–37 preservados | Preparado localmente; aguarda publicação |
+| R07 | Agente de validação / integrador | R06 | Evidências finais e CI das novas pontas | Validado localmente; CI remoto após publicação |
+| R08 | Integrador | R07; registrar situação de R05 | Matriz de atendimento e respostas prontas | Validado; respostas preparadas |
+
+R02, a preparação de R04 e a coleta de pré-requisitos de R05 podem ocorrer em
+paralelo com R01. R01 e R03 alteram `R/alert_functions.R`: integrar em sequência.
+R04 e R07 podem precisar do mesmo runner e de recursos de Docker: reservar a execução.
+O ambiente externo de R05 não bloqueia correções de código, mas impede declarar
+a auditoria concluída e a migração pronta.
+
+## 4. Contrato de entrega obrigatório para cada agente
+
+Ao receber uma tarefa, ler este documento e cumprir somente os IDs atribuídos.
+Antes de editar, confirmar branch, commit-base, árvore de trabalho e dependências.
+Não sobrescrever trabalho alheio. Preservar `plano_refatoracao_alerttools.html`
+e `plano_refatoracao_alerttools.qmd`, que já estavam sem rastreamento.
+
+Entregar ao integrador:
+
+1. ID da tarefa, estado e commit-base completo.
+2. Commits produzidos e arquivos alterados.
+3. Correspondência entre pedido do review, implementação e teste.
+4. Comandos executados, resultados, skips, limitações e evidências.
+5. Dependências externas ou decisões ainda necessárias.
+6. Texto de resposta ao revisor, sem publicá-lo automaticamente.
+
+Estados permitidos: `A fazer`, `Em execução`, `Implementado; falta validar`,
+`Validado`, `Pendente de ambiente externo`, `Preparado localmente; aguarda publicação`
+e `Validado localmente; CI remoto após publicação`. Teste ignorado não é teste aprovado.
+Não usar contagens antigas de checks como evidência da revisão nova.
+
+## 5. R00 — Atualizar referências e proteger o histórico
+
+### Ações
+
+- Consultar GitHub para estado, head/base e comentários atuais dos PRs #20 e #27–37.
+- Atualizar refs remotas sem descartar alterações locais.
+- Registrar SHA completo de cada ponta e base em um manifesto de execução.
+- Criar refs locais de segurança com prefixo `codex/backup-review-2026-10-29/`.
+ Não publicar backups sem necessidade.
+- Registrar os limites das séries antigas: #28 inclui #29 remoto; #30 antigo
+ contém o commit original do #29; #31–37 formam a cadeia anterior.
+- Conferir se há novos commits em `master`. A candidata já contém o `master`
+ verificado; não reescrever o #20 sem necessidade.
+
+### Aceite
+
+Manifesto permite recuperar cada branch. Merges #27/#29 identificados.
+Mudanças locais preservadas. Nenhuma branch remota reescrita nesta tarefa.
+
+## 6. R01 — Corrigir a perda de parâmetros no #28
+
+Review: https://github.com/AlertaDengue/AlertTools/pull/28#issuecomment-6447839399
+
+### Arquivos de partida
+
+- `R/alert_functions.R`: `.as_legacy_alert_objects()`, `.legacy_alert_parameters()`
+ e implementação de histórico.
+- `R/api.R`: wrapper `tabela_historico()`.
+- Solução existente no commit `15e0915` do #37.
+- `tests/testthat/test-api.R`; criar teste focado se necessário.
+
+### Ações
+
+- Extrair do #37 somente a preservação dos parâmetros como atributos dos filhos
+ e sua recuperação quando a lista externa perdeu o atributo.
+- Manter os campos públicos dos objetos `alerta` e o atributo externo existente.
+- Recuperar parâmetros sem nova leitura implícita do banco.
+- Testar dois municípios com parâmetros diferentes, concatenados exatamente com
+ a operação `do.call(c, ...)` usada no consumidor.
+- Comparar histórico combinado com históricos individuais pelas chaves, valores
+ e parâmetros; reproduzir o problema antes da correção.
+- Cobrir parâmetros ausentes e conflitantes com erro claro. Não escolher
+ silenciosamente o primeiro conjunto de parâmetros.
+- Manter no #37 o cenário integrado com as funções reais do consumidor.
+
+### Aceite
+
+Concatenação funciona, histórico preservado e nenhuma consulta adicional ao banco.
+Defaults legados de conexão e data, formato dos objetos e comportamento do #29 preservados.
+O #28 pode ser revisado sem depender de código exclusivo do #37.
+
+## 7. R02 — Corrigir testes e documentação de depreciação no #30
+
+Review: https://github.com/AlertaDengue/AlertTools/pull/30#issuecomment-6448407990
+
+### Arquivos de partida
+
+- `R/api.R`: `.deprecate_api()`.
+- `tests/testthat/test-api.R`.
+- `docs/refactoring/api-migration.md` e `transition-policy.dcf`.
+- `NEWS.md` e documentação gerada, se afetados.
+
+### Ações
+
+- Separar a leitura da versão instalada da decisão de emitir warning, usando
+ helper interno testável ou dependência interna substituível.
+- Não alterar a assinatura pública dos wrappers nem a versão em `DESCRIPTION`
+ para simular testes.
+- Testar 1.2.0 e outra versão 1.2.x sem aviso; 1.3.0 e versão posterior com aviso.
+- Testar a decisão e ao menos a emissão real via `lifecycle`, controlando sua
+ supressão por sessão para que o teste não dependa da ordem de execução.
+- Alinhar o guia à política já aprovada e ao início dos avisos em 1.3.0.
+
+### Aceite
+
+Os dois lados da fronteira 1.3.0 são exercitados. Os testes não ocultam todos os
+warnings globalmente. Documentação e implementação expressam a mesma política.
+
+## 8. R03 — Tornar #31 e #32 consistentes e independentes
+
+Reviews:
+
+- https://github.com/AlertaDengue/AlertTools/pull/31#issuecomment-6449473906
+- https://github.com/AlertaDengue/AlertTools/pull/32#issuecomment-6463503608
+
+### Arquivos de partida
+
+- `R/core_pipeline.R`: normalização, `.validate_pipeline_inputs()`, grupos de
+ cálculo e `.filter_case_records_for_group()`.
+- `R/alert_functions.R`: `.as_legacy_alert_objects()`.
+- `tests/testthat/test-core-pipeline.R`, `test-api.R` e helpers de fixtures.
+- Implementação município/doença já existente em `3d62c68`.
+
+### Entrega R03-A, no #31
+
+- Antecipar do #32 o processamento por município + doença e as validações
+ necessárias; não deixar a unidade de cálculo diferente da unidade validada.
+- Preservar aliases legados apenas nas fronteiras previstas.
+- Exigir correspondência dos conjuntos município/doença entre casos e parâmetros,
+ incluindo ambos os sentidos; apontar os pares problemáticos no erro.
+- Filtrar também os registros individuais de casos por doença. Rejeitar registros
+ ambíguos quando um município tiver múltiplas doenças e faltar essa identificação.
+- Garantir que o join climático município/semana não multiplique casos.
+
+### Entrega R03-B, no #32
+
+- Retirar do diff o processamento antecipado para o #31.
+- Antes de montar qualquer objeto legado, validar que o resultado contém uma
+ única doença coerente nos dados e parâmetros; rejeitar múltiplos CID10.
+- Manter o processamento de múltiplas doenças disponível na API moderna.
+- Atualizar título/descrição do #32 para o escopo residual real.
+
+### Matriz mínima de testes
+
+| Cenário | Resultado esperado |
+|---|---|
+| Um município, dengue + chikungunya | API moderna calcula grupos separados |
+| Dois municípios, pares diferentes de doenças | Mesmas saídas das execuções isoladas, alinhadas por chave |
+| Parâmetro ausente ou excedente | Erro anterior ao cálculo, com par identificado |
+| Chaves duplicadas em casos, clima ou parâmetros | Erro; nenhuma multiplicação silenciosa |
+| Registros individuais sem doença em entrada ambígua | Erro explícito |
+| Resultado com múltiplas doenças enviado ao conversor legado | Erro explícito antes da conversão |
+| Vários municípios de uma doença no legado | Contrato e recuperação de parâmetros preservados |
+
+### Aceite
+
+#31 já é coerente sozinho. #32 acrescenta a proteção legada sem duplicar código.
+Reordenar entradas não mistura doenças. Testes de clima ausente e histórico continuam passando.
+
+## 9. R04 — Validar INLA real e concorrência no #34
+
+Review: https://github.com/AlertaDengue/AlertTools/pull/34
+Usar também o texto atual da revisão no GitHub; o pedido inclui resultado,
+tempo, memória, risco de OOM e concorrência externa por estados em host/Docker.
+
+### Arquivos de partida e entregas previstas
+
+- `R/nowcasting_fun.R`, `R/adjust_incidence_functions.R`, `R/core_pipeline.R`.
+- `tests/testthat/test-concurrency.R`, `test-optional-models.R`.
+- `tools/benchmark-concurrency.R` e `.py`.
+- `tests/reference/comparison.R`, helpers e comparação do #36.
+- Novo teste `test-inla-integration.R` e runner `tools/run-inla-integration.R`.
+- `.github/workflows/R-CMD-check.yaml`, `docs/refactoring/concurrency.md`.
+- Evidências novas em `docs/refactoring/evidence/`, sem sobrescrever as de 22/10.
+
+### R04-A — Protocolo antes da medição
+
+- Construir entrada controlada com notificações suficientes para executar de
+ fato o ramo bayesiano, com dois ou mais municípios e múltiplas doenças.
+- Confirmar os nomes efetivos dos modos aceitos; não supor que o modo `none`
+ exercita INLA nem usar mocks no teste que comprova execução real.
+- Fixar dados, sementes, referência, versão candidata, R, INLA e bibliotecas numéricas.
+- Registrar uma política de comparação antes de rodar referência e candidata:
+ colunas, chaves, tolerâncias absolutas/relativas e tratamento de NA.
+- Usar repetição serial para caracterizar reprodutibilidade. Divergência acima
+ da tolerância exige investigação; não ampliar tolerância apenas para aprovar.
+- Definir limites de tempo/memória e tamanho da carga. Não provocar OOM no host.
+
+### R04-B — Correção numérica e isolamento
+
+- Comparar serial/paralelo na candidata e referência/candidata com o mesmo
+ ambiente INLA, entradas e parâmetros. Declarar a adaptação de leitura usada
+ pela referência; não apresentar isso como instalação completa do sistema antigo.
+- Comparar casos estimados e intervalos, incidência, Rt, probabilidades,
+ níveis de alerta e histórico; valores categóricos e chaves devem coincidir.
+- Separar ajuste multithread da amostragem posterior, que usa `1:1` com semente.
+- Verificar que grupos não compartilham séries, sementes ou parâmetros por engano
+ e que opções globais do INLA não são alteradas pelo pacote.
+- Se houver diferenças nos níveis de alerta, falhar e explicar a causa,
+ mesmo quando diferenças numéricas pequenas estiverem dentro da tolerância.
+
+### R04-C — Tempo, memória e comportamento operacional
+
+- Medir inicialmente a matriz `estados externos = 1/2`,
+ `municipality_workers = 1/2`, `inla_threads = 1/2`, com três repetições.
+ Ajustar o tamanho da carga ao orçamento e registrar qualquer configuração não executada.
+- Executar baseline e matriz no host e em Docker com limites explícitos de CPU
+ e memória. Comparar cada ambiente com seu próprio baseline, sem confundir
+ diferenças de infraestrutura com mudanças do pacote.
+- Registrar tempo, exit code, timeout, árvore de processos, RSS agregado amostrado
+ e, em Docker/cgroup, pico do grupo e ocorrência de OOM quando disponíveis.
+ Explicitar limitações do RSS e evitar alegar que um teste pequeno elimina risco de OOM.
+- Exercitar falha controlada de um município e recuperação após falha estadual;
+ verificar subprocessos encerrados, ausência de resultados parciais tratados
+ como completos e consistência de `.RData`, histórico e SQL.
+- Não aumentar defaults 1/1. Recomendar orçamento externo com base nos resultados,
+ deixando a escolha operacional para o consumidor.
+
+### R04-D — CI e evidências
+
+- Criar job Linux reduzido com INLA real, dependência explícita e timeout.
+ Falha ao instalar ou executar INLA deve falhar o job; não transformar em skip verde.
+- Testes locais gerais podem continuar opcionais sem INLA; o runner dedicado
+ deve confirmar que os cenários obrigatórios realmente foram executados.
+- Publicar artefatos de diagnóstico mesmo em falha. Benchmark amplo pode rodar
+ separadamente do CI por PR; anexar seu protocolo e resultados à revisão.
+- Relatório deve conter SHAs, hashes das entradas, versões, sementes,
+ configuração de recursos, CSV das comparações e medições por repetição.
+
+### Aceite
+
+Há evidência de INLA real, equivalência dentro do protocolo, alertas coerentes,
+recuperação testada e medições de host/Docker identificadas. Se faltar Docker,
+dados representativos ou recursos, marcar essa parte pendente e continuar os
+demais itens; não declarar migração pronta.
+
+## 10. R05 — Auditoria Zika em homologação
+
+Pedido: revisão do #33, que condiciona a migração à auditoria em homologação.
+
+### Pré-requisitos e ações
+
+- Identificar a lista de municípios realmente pretendida para a migração.
+- Obter acesso de leitura ao banco de homologação pelo mecanismo de credenciais
+ existente, sem imprimir, salvar no repositório ou enviar segredos nos relatórios.
+- Usar `tools/audit-zika-coverage.R` com a candidata identificada, transação
+ somente leitura e entradas/saídas em diretório seguro.
+- Confirmar o comportamento de A92.8 específico na API nova e A90 no wrapper
+ legado; parâmetros explícitos do consumidor continuam respeitados.
+- Contabilizar `specific`, `legacy_only`, `missing`, `duplicate`, listar ações
+ necessárias e identificar quem mantém os parâmetros. Não alterar esses dados.
+- Publicar somente evidência agregada ou dados permitidos; informar o local
+ protegido do relatório completo quando não puder ser versionado.
+
+### Aceite
+
+Cobertura medida no recorte real e identificada por data, ambiente e revisão.
+Ausências e duplicidades não são mascaradas. Troca da política legada depende
+da resolução dos dados e da avaliação responsável, não só de testes sintéticos.
+Sem acesso ou lista de municípios: `Pendente de ambiente externo`, com requisito preciso.
+
+## 11. R06 — Runbook de rebase e preservação dos PRs aprovados
+
+Executar por um integrador, após preparar correções e backups. Não aplicar uma
+receita de rebase à cadeia inteira sem examinar os limites de cada série.
+
+1. Reconstruir #28 a partir da ponta remota que contém o merge #29. Incorporar
+ a base candidata atual e R01. Se a candidata não avançou, evitar rebase sem efeito.
+2. Reconstruir #30 sobre o novo #28, reaplicando somente sua alteração de
+ depreciação e R02. O commit original de #29 na série antiga não deve reaparecer
+ como alteração nova: sua implementação já está no novo pai.
+3. Reconstruir #31 sobre #30; reaplicar normalização e R03-A.
+4. Reconstruir #32 sobre #31; retirar duplicações de R03-A e aplicar R03-B.
+5. Reaplicar #33 sobre #32, preservando a política Zika e seu teste de data.
+6. Reaplicar #34 sobre #33 e acrescentar R04.
+7. Reaplicar #35 sobre #34 sem alterar seu contrato aprovado de histórico mínimo.
+8. Reaplicar #36 sobre #35, preservando snapshots, integridade LF/CRLF e correção
+ de IDs legados. Acrescentar documentação de evidência bayesiana quando produzida.
+9. Reaplicar #37 sobre #36. Remover apenas a implementação já movida para #28;
+ preservar testes integrados, precisão SQL, replay PostgreSQL e artefatos.
+
+Em cada passo:
+
+- Analisar `git log`, merge-base e `git diff ...`.
+- Usar limites antigos registrados em R00 para `rebase --onto`, ou reaplicar
+ commits selecionados quando a transferência parcial exigir reconstrução.
+ Nunca usar `--skip` apenas porque um conflito é difícil.
+- Comparar séries com `git range-diff`; para merges/transferências parciais,
+ complementar com diff de árvores e testes dos contratos envolvidos.
+- Registrar a movimentação de cada trecho #37→#28 e #32→#31 no manifesto.
+- Conferir que o diff próprio de cada PR não traz todos os commits do #20.
+
+Publicação:
+
+- Verificar novamente as pontas remotas antes de publicar.
+- Usar lease associado ao SHA remoto observado, nunca `push --force` irrestrito.
+ Se o lease falhar, reconciliar o trabalho novo; não sobrescrever.
+- Publicar na ordem dos pais para os filhos, mantendo as bases coerentes.
+- Não abrir PR novo para substituir um existente e não fechar #35–37.
+- Quando houver merge futuro, ajustar a base dos descendentes para a branch
+ que recebeu aquele merge. Não apontar tudo para `master` enquanto #20 estiver aberto.
+- Revisões podem ser invalidadas por novas pontas; não declarar a aprovação
+ histórica dos #35–37 como aprovação automática do novo conteúdo.
+
+### Aceite
+
+Todos os commits esperados presentes; nenhum merge perdido; nenhuma alteração
+alheia sobrescrita. Matriz de PRs atualizada com base, head, diff e justificativa.
+
+## 12. R07 — Validação final e evidência por revisão
+
+Os comandos abaixo são pontos de entrada, a executar na branch apropriada e
+somente depois de conferir seus pré-requisitos. Guardar saídas por SHA.
+
+```sh
+# R01/R02 e fronteira legada
+Rscript -e 'devtools::test(filter = "api", stop_on_failure = TRUE)'
+
+# R03, além dos testes novos específicos
+Rscript -e 'devtools::test(filter = "core-pipeline", stop_on_failure = TRUE)'
+
+# R04: inclui runner dedicado sem skips; nome definido na entrega
+Rscript tools/run-inla-integration.R /tmp/alerttools-review-inla-evidence
+
+# Comparações e integração já existentes na ponta da cadeia
+Rscript tools/compare-epidemiology.R /tmp/alerttools-review-epidemiology
+Rscript -e 'devtools::test(filter = "consumer-integration", stop_on_failure = TRUE)'
+
+# Executar somente em PostgreSQL descartável alerttools_test, com PG* configurados
+ALERTTOOLS_TEST_POSTGRES=true PGDATABASE=alerttools_test \
+ Rscript tools/run-postgres-integration.R /tmp/alerttools-review-consumer-evidence
+
+# Suíte completa após consolidação
+Rscript -e 'devtools::test(stop_on_failure = TRUE)'
+```
+
+- Se testes novos forem separados de `test-api.R`, acrescentar seus filtros aos
+ comandos de R01/R02/R03 no relatório; não supor que o filtro acima os cobre.
+- RPostgres/PostgreSQL devem usar apenas banco de teste dedicado: o helper recria schemas.
+- Executar documentação e check do pacote conforme o workflow existente.
+ Não chamar um check com vignettes desabilitadas de equivalente ao CI completo.
+- Verificar todos os jobs dos PRs alterados no SHA publicado, incluindo o novo
+ job INLA. Separar falha de infraestrutura de falha de código, sem ignorar nenhuma.
+- Não atribuir equivalência bayesiana aos relatórios antigos feitos no modo `none`.
+
+### Aceite
+
+Testes pertinentes aprovados; testes obrigatórios de PostgreSQL e INLA não ignorados;
+diffs dentro do escopo; CI verde nas novas pontas. Pendências de homologação e
+validação científica registradas separadamente do aceite de código.
+
+## 13. R08 — Matriz de atendimento e passagem para revisão
+
+Entregar relatório final com uma linha para cada pedido, usando este formato:
+
+| Pedido / fonte | PR destino | Commit | Teste / evidência | Resultado | Pendência |
+|---|---|---|---|---|---|
+| Perda de parâmetros no fallback (#28) | #28 | Preencher | Preencher | Pendente | — |
+| Avisos em 1.3.0 (#30) | #30 | Preencher | Preencher | Pendente | — |
+| Política aprovada no guia (#30) | #30 | Preencher | Preencher | Pendente | — |
+| Município/doença em todo o cálculo (#31) | #31 | Preencher | Preencher | Pendente | — |
+| Correspondência exata de pares (#31) | #31 | Preencher | Preencher | Pendente | — |
+| Rejeição de múltiplas doenças no legado (#32) | #32 | Preencher | Preencher | Pendente | — |
+| Auditoria Zika (#33) | #33 | Preencher | Preencher | Pendente | Ambiente/dados |
+| INLA real e comparação numérica (#34/#36) | #34/#36 | Preencher | Preencher | Pendente | — |
+| Concorrência, memória e tempo host/Docker (#34) | #34 | Preencher | Preencher | Pendente | Ambiente |
+| Falhas e recuperação com INLA (#34/#37) | #34/#37 | Preencher | Preencher | Pendente | — |
+| Atualização de bases e diffs (#28/#30–37) | Cadeia | Preencher | Range-diff/CI | Pendente | — |
+
+Atualizar títulos/descrições ao escopo final; preparar respostas curtas com links
+para commits, testes e evidências. Não marcar comentários como resolvidos apenas
+por haver código semelhante em um PR posterior.
+
+## 14. Prompt de despacho reutilizável
+
+Copiar o bloco abaixo e substituir os campos antes de atribuir a um agente:
+
+> Execute a tarefa [ID] de
+> `docs/refactoring/plano-correcao-reviews-2026-10-29.md` no checkout [CAMINHO],
+> branch [BRANCH], a partir do commit [SHA COMPLETO]. Dependências disponíveis:
+> [IDs/COMMITS]. Leia a tarefa, o contrato de entrega e as restrições gerais.
+> Trabalhe somente no escopo atribuído. Não faça merge, release, publicação de
+> mensagens ou rebase/push de outras branches. Se houver trabalho concorrente,
+> use o checkout isolado atribuído. Entregue commits, testes executados,
+> evidências, pendências e uma resposta pronta ao review. Não declare aprovação
+> de teste ignorado nem modifique referências históricas para acomodar a candidata.
+
+O integrador recebe R00/R06/R08; agentes especialistas recebem os demais IDs.
+Um agente pode executar a sequência inteira de forma serial se não houver
+delegação. Este documento não dispara agentes nem executa suas tarefas.
diff --git a/tests/reference/consumer-27a03f26/functions.R b/tests/reference/consumer-27a03f26/functions.R
new file mode 100644
index 0000000..986687c
--- /dev/null
+++ b/tests/reference/consumer-27a03f26/functions.R
@@ -0,0 +1,110 @@
+# Unmodified expressions from AlertaDengueAnalise/main/main_BR.R
+# Commit 27a03f26a9bf366597ef135e7da8d2f620ea9a8e
+safe_gc <- function() {
+ invisible(gc(verbose = FALSE))
+}
+combine_ale_parts <- function(parts) {
+ parts <- Filter(Negate(is.null), parts)
+ if (length(parts) == 0) {
+ return(NULL)
+ }
+ do.call(c, c(parts, recursive = FALSE))
+}
+run_city_pipeline <- function(city, cid10, now_mode, disease_label, sig) {
+ log_msg("[state] ", sig, " ", disease_label, " city=", city, " started")
+ result <- tryCatch({
+ withCallingHandlers(pipe_infodengue(city, cid10 = cid10, nowcasting = now_mode, finalday = report_end_date,
+ narule = "arima", iniSE = 201001, dataini = "sinpri", completetail = 0), warning = function(w) {
+ log_msg("[state] ", sig, " ", disease_label, " city=", city, " warning: ", conditionMessage(w),
+ level = "WARN")
+ invokeRestart("muffleWarning")
+ })
+ }, error = function(e) {
+ log_msg("[state] ", sig, " ", disease_label, " city=", city, " failed: ", conditionMessage(e),
+ level = "ERROR")
+ NULL
+ })
+ if (is.null(result)) {
+ log_msg("[state] ", sig, " ", disease_label, " city=", city, " returned no result after fallback execution",
+ level = "WARN")
+ }
+ result
+}
+run_disease_pipeline_by_city <- function(cidades, cid10, now_mode, disease_label, sig) {
+ log_msg(" - ", disease_label, ": retrying municipality-level execution after state-level failure")
+ ale_parts <- vector("list", length(cidades))
+ for (j in seq_along(cidades)) {
+ city <- cidades[[j]]
+ ale_parts[[j]] <- run_city_pipeline(city, cid10, now_mode, disease_label, sig)
+ safe_gc()
+ }
+ ale <- combine_ale_parts(ale_parts)
+ rm(ale_parts)
+ safe_gc()
+ if (is.null(ale)) {
+ stop("All municipality executions failed for ", sig, " / ", disease_label, call. = FALSE)
+ }
+ restab <- tabela_historico(ale, iniSE = report_epiweek - window_weeks)
+ list(ale = ale, restab = restab)
+}
+run_disease_pipeline <- function(cidades, cid10, now_mode, disease_label, sig) {
+ tryCatch({
+ ale <- pipe_infodengue(cidades, cid10 = cid10, nowcasting = now_mode, finalday = report_end_date,
+ narule = "arima", iniSE = 201001, dataini = "sinpri", completetail = 0)
+ restab <- tabela_historico(ale, iniSE = report_epiweek - window_weeks)
+ list(ale = ale, restab = restab)
+ }, error = function(e) {
+ log_msg("[state] ", sig, " ", disease_label, " failed in state-level execution: ", conditionMessage(e),
+ level = "ERROR")
+ log_msg("[state] ", sig, " ", disease_label, " fallback: municipality-level isolation", level = "WARN")
+ run_disease_pipeline_by_city(cidades, cid10, now_mode, disease_label, sig)
+ })
+}
+load_state_result <- function(path) {
+ env <- new.env(parent = emptyenv())
+ load(path, envir = env)
+ if (!exists("res", envir = env, inherits = FALSE)) {
+ stop("Missing object 'res' inside: ", path, call. = FALSE)
+ }
+ env$res
+}
+append_part <- function(parts, value) {
+ if (!is.null(value)) {
+ parts[[length(parts) + 1]] <- value
+ }
+ parts
+}
+normalize_restab <- function(x) {
+ if (is.null(x)) {
+ return(NULL)
+ }
+ if (is.list(x) && !is.data.frame(x)) {
+ return(dplyr::bind_rows(x))
+ }
+ x
+}
+normalize_ale <- function(x) {
+ if (is.null(x)) {
+ return(NULL)
+ }
+ tr <- transpose(x)
+ data <- dplyr::bind_rows(tr[[1]])
+ idx <- dplyr::bind_rows(tr[[2]])
+ cbind(data, idx)
+}
+bind_parts <- function(parts) {
+ parts <- Filter(Negate(is.null), parts)
+ if (length(parts) == 0) {
+ return(NULL)
+ }
+ dplyr::bind_rows(parts)
+}
+cap_max <- function(df) {
+ if (is.null(df)) {
+ return(NULL)
+ }
+ if ("casos_est_max" %in% names(df)) {
+ df$casos_est_max[df$casos_est_max > 10000] <- NA
+ }
+ df
+}
diff --git a/tests/reference/consumer-27a03f26/manifest.csv b/tests/reference/consumer-27a03f26/manifest.csv
new file mode 100644
index 0000000..03a58f3
--- /dev/null
+++ b/tests/reference/consumer-27a03f26/manifest.csv
@@ -0,0 +1,3 @@
+"file","consumer_commit","source","source_git_blob","approved_alerttools","md5"
+"functions.R","27a03f26a9bf366597ef135e7da8d2f620ea9a8e","main/main_BR.R","863937b5b77389c5341a103522bb59c8a75d5789","e460b3b8c15ab28e8755f482d576cf7280803b34","073dea5b77d1dec9e485a2f1c6c2d41c"
+"publication.R","27a03f26a9bf366597ef135e7da8d2f620ea9a8e","main/main_BR.R","863937b5b77389c5341a103522bb59c8a75d5789","e460b3b8c15ab28e8755f482d576cf7280803b34","5df1e544d8ba8ab07a70b4b4ac113fba"
diff --git a/tests/reference/consumer-27a03f26/publication.R b/tests/reference/consumer-27a03f26/publication.R
new file mode 100644
index 0000000..a91f63b
--- /dev/null
+++ b/tests/reference/consumer-27a03f26/publication.R
@@ -0,0 +1,23 @@
+# Unmodified expressions from AlertaDengueAnalise/main/main_BR.R
+# Commit 27a03f26a9bf366597ef135e7da8d2f620ea9a8e
+if (!is.null(restab_den)) {
+ out_sql <- file.path(sql_dir, "output_dengue.sql")
+ log_msg("Writing SQL dengue: ", out_sql)
+ write_alerta(restab_den, writetofile = TRUE, arq = out_sql)
+} else {
+ log_msg("No dengue restab found. Skipping dengue SQL.", level = "WARN")
+}
+if (!is.null(restab_chik)) {
+ out_sql <- file.path(sql_dir, "output_chik.sql")
+ log_msg("Writing SQL chik: ", out_sql)
+ write_alerta(restab_chik, writetofile = TRUE, arq = out_sql)
+} else {
+ log_msg("No chik restab found. Skipping chik SQL.", level = "WARN")
+}
+if (!is.null(restab_zika)) {
+ out_sql <- file.path(sql_dir, "output_zika.sql")
+ log_msg("Writing SQL zika: ", out_sql)
+ write_alerta(restab_zika, writetofile = TRUE, arq = out_sql)
+} else {
+ log_msg("No zika restab found. Skipping zika SQL.", level = "WARN")
+}
diff --git a/tests/reference/e460b3b8/alert_functions.R b/tests/reference/e460b3b8/alert_functions.R
index 4d39ca5..a4716a9 100644
--- a/tests/reference/e460b3b8/alert_functions.R
+++ b/tests/reference/e460b3b8/alert_functions.R
@@ -180,3 +180,71 @@ tabela_historico <- function(obj, iniSE, lastSE, type = "all", versao = Sys.Date
return(NULL)
}
}
+write_alerta <- function(d, writetofile = FALSE, datasource = con, arq = "output.sql") {
+ assert_that(class(d) == "data.frame", msg = "write_alerta: d is not a data.frame. d should\n be an output from tabela_historico.")
+ if (writetofile == FALSE)
+ assert_that(class(datasource) == "PostgreSQLConnection", msg = "write_alerta: \n works only for writing into Infodengue's server")
+ cid10 = unique(d$CID10)
+ assert_that(length(cid10) == 1, msg = "write_alerta: d must contain only one cid10")
+ dcolumns <- c("SE", "data_iniSE", "casos_est", "casos_est_min", "casos_est_max", "casos", "casprov",
+ "municipio_geocodigo", "p_rt1", "p_inc100k", "Localidade_id", "nivel", "id", "versao_modelo",
+ "municipio_nome", "Rt", "pop", "receptivo", "transmissao", "nivel_inc", "temp_min", "temp_med",
+ "temp_max", "umid_min", "umid_med", "umid_max")
+ if (!("temp_min" %in% names(d)))
+ d$temp_min <- NA
+ if (!("umid_max" %in% names(d)))
+ d$umid_max <- NA
+ assert_that(all(dcolumns %in% names(d)), msg = "write_alerta: check if d contains required\n columns")
+ if (cid10 == "A90") {
+ tabela <- "Historico_alerta"
+ constr.unico = "alertas_unicos"
+ }
+ if (cid10 == "A92.0") {
+ tabela <- "Historico_alerta_chik"
+ constr.unico = "alertas_unicos_chik"
+ }
+ if (cid10 == "A92.8") {
+ tabela <- "Historico_alerta_zika"
+ constr.unico = "alertas_unicos_zika"
+ }
+ if (!(cid10 %in% c("A90", "A92.0", "A92.8")))
+ stop(paste("não sei onde salvar histórico para o agravo", cid10))
+ dados <- d %>% select(all_of(dcolumns))
+ varnamesforsql <- c("\"SE\"", "\"data_iniSE\"", "casos_est", "casos_est_min", "casos_est_max", "casos",
+ "casprov", "municipio_geocodigo", "p_rt1", "p_inc100k", "\"Localidade_id\"", "nivel", "id", "versao_modelo",
+ "municipio_nome", "\"Rt\"", "pop", "tempmin", "tempmed", "tempmax", "umidmin", "umidmed", "umidmax",
+ "receptivo", "transmissao", "nivel_inc")
+ varnames.sql <- str_c(varnamesforsql, collapse = ",")
+ updates = str_c(paste(varnamesforsql, "=excluded.", varnamesforsql, sep = ""), collapse = ",")
+ escreve_linha <- function(li) {
+ vetor <- dados[li, ]
+ vetor$municipio_nome = gsub(vetor$municipio_nome, pattern = "'", replacement = "''")
+ linha = paste0(vetor$SE, ",'", as.character(vetor$data_iniSE), "',", str_c(vetor[1, c("casos_est",
+ "casos_est_min", "casos_est_max", "casos", "casprov", "municipio_geocodigo", "p_rt1", "p_inc100k",
+ "Localidade_id", "nivel", "id")], collapse = ","), ",'", as.character(vetor$versao_modelo),
+ "','", as.character(vetor$municipio_nome), "',", str_c(vetor[1, c("Rt", "pop", "temp_min",
+ "temp_med", "temp_max", "umid_min", "umid_med", "umid_max")], collapse = ","), ",", str_c(vetor[1,
+ c("receptivo", "transmissao", "nivel_inc")], collapse = ","))
+ linha = gsub("NA", "NULL", linha)
+ linha = gsub("NaN", "NULL", linha)
+ insert_sql = paste("INSERT INTO \"Municipio\".\"", tabela, "\" (", varnames.sql, ") VALUES (",
+ linha, ") \n ON CONFLICT ON CONSTRAINT ", constr.unico,
+ " \n DO UPDATE SET ", updates, ";", sep = "")
+ if (writetofile == FALSE) {
+ try(dbGetQuery(datasource, insert_sql))
+ }
+ insert_sql
+ }
+ if (writetofile) {
+ f <- file(arq, open = "w", encoding = "utf8")
+ for (i in 1:nrow(d)) writeLines(escreve_linha(i), f)
+ message("writing alerta into file ", arq)
+ close(f)
+ }
+ else {
+ print(paste("writing alerta into table", tabela))
+ try(dbGetQuery(datasource, "BEGIN TRANSACTION;"))
+ 1:nrow(d) %>% map(escreve_linha)
+ try(dbGetQuery(datasource, "COMMIT TRANSACTION;"))
+ }
+}
diff --git a/tests/reference/e460b3b8/manifest.csv b/tests/reference/e460b3b8/manifest.csv
index 608b075..35e8867 100644
--- a/tests/reference/e460b3b8/manifest.csv
+++ b/tests/reference/e460b3b8/manifest.csv
@@ -1,5 +1,5 @@
"file","source","git_blob","reference_commit","functions","md5"
-"alert_functions.R","R/alert_functions.R","5d0ca6fb16fbbe84ae9aa53a8f30036774630844","e460b3b8c15ab28e8755f482d576cf7280803b34","setCriteria;fouralert;calc.alerta;tabela_historico","92746d601e2a3f78c16d893210344396"
+"alert_functions.R","R/alert_functions.R","5d0ca6fb16fbbe84ae9aa53a8f30036774630844","e460b3b8c15ab28e8755f482d576cf7280803b34","setCriteria;fouralert;calc.alerta;tabela_historico;write_alerta","16f5b14a391903f2e7a8d9a256e835e1"
"Rt_functions.R","R/Rt_functions.R","6b756daaf92f4f38957b6cff6ab04c16672a54d1","e460b3b8c15ab28e8755f482d576cf7280803b34","Rt;betaconf;ll","9a03840a0c721cb0402146a988235557"
"adjust_incidence_functions.R","R/adjust_incidence_functions.R","411ab2302796553ab7b844ba0f990e8a6836eba7","e460b3b8c15ab28e8755f482d576cf7280803b34","adjustIncidence;bayesnowcasting","f9a679f169fbe003f9d9e2b7c5e6ee91"
"nowcasting_fun.R","R/nowcasting_fun.R","ecd2802e8e0397e259ea3f6ba450af2ef2d3d6f0","e460b3b8c15ab28e8755f482d576cf7280803b34","ff;gg;nowcasting;nowcast.INLA","dd3473088f3bbe904b4ca046d71b3252"
diff --git a/tests/testthat/helper-consumer.R b/tests/testthat/helper-consumer.R
new file mode 100644
index 0000000..5487f00
--- /dev/null
+++ b/tests/testthat/helper-consumer.R
@@ -0,0 +1,176 @@
+consumer_fixture_database <- function(backend, test_env = parent.frame()) {
+ conn <- if (backend == "postgres") postgres_fixture_connection(test_env) else
+ sqlite_fixture_connection(test_env)
+ if (backend == "postgres") {
+ DBI::dbExecute(conn, 'CREATE SCHEMA "weather"')
+ withr::defer(DBI::dbExecute(conn, 'DROP SCHEMA "weather" CASCADE'), envir = test_env)
+ }
+ codes <- c(3304557, 3303302)
+ combine <- function(factory, column) do.call(rbind, lapply(codes, function(code) {
+ value <- factory()
+ value[[column]] <- code
+ value
+ }))
+ notifications <- combine(notification_fixture, "municipio_geocodigo")
+ notifications <- do.call(rbind, lapply(c("A90", "A92.0", "A92.8"), function(disease) {
+ value <- notifications
+ value$cid10_codigo <- disease
+ value
+ }))
+ climate <- combine(municipal_climate_fixture, "geocode")
+ if (backend == "sqlite") {
+ notifications[c("dt_notific", "dt_sin_pri", "dt_digita")] <-
+ lapply(notifications[c("dt_notific", "dt_sin_pri", "dt_digita")], as.numeric)
+ climate$date <- as.numeric(climate$date)
+ }
+ parameters <- combine(parameter_fixture, "municipio_geocodigo")
+ chik <- parameters
+ chik$cid10 <- "A92.0"
+ tables <- list(notifications = notifications, municipal_climate = climate,
+ municipalities = combine(municipality_fixture, "geocodigo"),
+ parameters = rbind(parameters, chik))
+ for (key in names(tables)) {
+ DBI::dbWriteTable(conn, consumer_table_id(conn, key), tables[[key]], overwrite = TRUE)
+ }
+ conn
+}
+
+consumer_table_id <- function(conn, key) {
+ backend <- AlertTools:::.db_backend(conn)
+ location <- AlertTools:::.db_table_config[[key]][[backend]]
+ if (backend == "postgres") DBI::Id(schema = location[[1]], table = location[[2]]) else
+ DBI::Id(table = location[[1]])
+}
+
+load_pinned_consumer <- function(conn, reference = FALSE, fail_state = FALSE,
+ failed_cities = numeric()) {
+ directory <- file.path(.reference_root, "tests/reference/consumer-27a03f26")
+ manifest <- utils::read.csv(file.path(directory, "manifest.csv"))
+ stopifnot(identical(reference_snapshot_md5(file.path(directory, manifest$file)),
+ manifest$md5))
+ consumer <- new.env(parent = asNamespace("AlertTools"))
+ sys.source(file.path(directory, "functions.R"), consumer)
+ consumer$events <- character()
+ consumer$log_msg <- function(..., level = "INFO") {
+ consumer$events <- c(consumer$events, paste0(level, ": ", paste0(..., collapse = "")))
+ invisible(NULL)
+ }
+ consumer$report_end_date <- as.Date("2021-02-13")
+ consumer$report_epiweek <- 202106
+ consumer$window_weeks <- 52
+ inject_fault <- function(cities) {
+ if ((fail_state && length(cities) > 1L) || any(cities %in% failed_cities)) {
+ stop("Injected consumer recovery test failure.")
+ }
+ }
+ if (!reference) {
+ consumer$pipe_infodengue <- function(cities, ...) {
+ inject_fault(cities)
+ AlertTools::pipe_infodengue(cities, ...)
+ }
+ } else {
+ parameters <- AlertTools:::.repo_parameters(conn, c(3304557, 3303302))
+ legacy <- load_epidemiological_reference(.reference_root, parameters)
+ consumer$tabela_historico <- legacy$tabela_historico
+ consumer$write_alerta <- legacy$write_alerta
+ consumer$pipe_infodengue <- function(cities, cid10, nowcasting, finalday,
+ narule, iniSE, dataini, completetail) {
+ inject_fault(cities)
+ # Controlled DB boundary: both versions read the same snapshot through DBI.
+ # Historical calculation, conversion and SQL writer bodies are unchanged.
+ parameters <- AlertTools:::.fetch_alert_parameters_impl(cities, cid10, conn)
+ cases <- AlertTools::fetch_cases(conn, cities, cid10, as.Date("2018-01-01"),
+ finalday, "symptom_onset", completetail)
+ climate <- AlertTools::fetch_climate(conn, cities,
+ AlertTools::epiweek_start(iniSE), finalday)
+ input <- dplyr::left_join(cases, climate,
+ by = c("cidade" = "geocodigo", "SE" = "SE"))
+ input$tweet <- NA_real_
+ input$inc <- input$casos / input$pop * 1e5
+ values <- lapply(cities, function(city) suppressMessages(legacy$calc.alerta(
+ city, list(input, AlertTools::as_epiweek(finalday), nowcasting, parameters, NULL)
+ )))
+ names(values) <- cities
+ values
+ }
+ }
+ consumer
+}
+
+consumer_known_warnings <- function(code) {
+ withCallingHandlers(code, warning = function(condition) {
+ if (grepl("Using dengue parameters", conditionMessage(condition), fixed = TRUE)) {
+ invokeRestart("muffleWarning")
+ }
+ })
+}
+
+consumer_physical_history <- function(history) {
+ value <- history[setdiff(names(history), "CID10")]
+ names(value) <- sub("^(temp|umid)_", "\\1", names(value))
+ rownames(value) <- NULL
+ value
+}
+
+consumer_history_table <- function(conn, history, key) {
+ id <- consumer_table_id(conn, key)
+ if (!DBI::dbExistsTable(conn, id)) {
+ DBI::dbWriteTable(conn, id, consumer_physical_history(history)[0, ])
+ keys <- paste(DBI::dbQuoteIdentifier(conn,
+ c("SE", "municipio_geocodigo", "Localidade_id")), collapse = ", ")
+ backend <- AlertTools:::.db_backend(conn)
+ suffix <- switch(key, alert_dengue = "", alert_chik = "_chik", alert_zika = "_zika")
+ name <- as.character(DBI::dbQuoteIdentifier(conn, paste0("alertas_unicos", suffix)))
+ table <- as.character(DBI::dbQuoteIdentifier(conn, id))
+ command <- if (backend == "postgres") paste("ALTER TABLE", table,
+ "ADD CONSTRAINT", name, "UNIQUE (", keys, ")") else
+ paste("CREATE UNIQUE INDEX", name, "ON", table, "(", keys, ")")
+ DBI::dbExecute(conn, command)
+ }
+ DBI::dbExecute(conn, paste("DELETE FROM", DBI::dbQuoteIdentifier(conn, id)))
+ id
+}
+
+consumer_ordered_rows <- function(value) {
+ value <- value[order(value$municipio_geocodigo, value$SE), , drop = FALSE]
+ # SQLite stores DBI dates as numeric days; PostgreSQL returns Date.
+ if (is.numeric(value$data_iniSE)) value$data_iniSE <- as.Date(value$data_iniSE,
+ origin = "1970-01-01")
+ rownames(value) <- NULL
+ value
+}
+
+consumer_publication <- function(consumer, result, directory, disease) {
+ dir.create(directory, recursive = TRUE, showWarnings = FALSE)
+ res <- list()
+ suffix <- switch(disease, A90 = "den", A92.0 = "chik", A92.8 = "zika")
+ res[[paste0("ale.", suffix)]] <- result$ale
+ res[[paste0("restab.", suffix)]] <- result$restab
+ state_file <- file.path(directory, "state.RData")
+ save(res, file = state_file)
+ decoded <- consumer$load_state_result(state_file)
+ consumer$sql_dir <- directory
+ consumer$restab_den <- if (disease == "A90") result$restab else NULL
+ consumer$restab_chik <- if (disease == "A92.0") result$restab else NULL
+ consumer$restab_zika <- if (disease == "A92.8") result$restab else NULL
+ suppressMessages(sys.source(file.path(.reference_root,
+ "tests/reference/consumer-27a03f26/publication.R"), consumer))
+ sql <- file.path(directory, switch(disease, A90 = "output_dengue.sql",
+ A92.0 = "output_chik.sql", A92.8 = "output_zika.sql"))
+ list(state = state_file, sql = sql, decoded = decoded,
+ history = decoded[[paste0("restab.", suffix)]],
+ data = consumer$normalize_ale(decoded[[paste0("ale.", suffix)]]))
+}
+
+record_consumer_evidence <- function(backend, name, report, candidate, reference) {
+ output <- Sys.getenv("ALERTTOOLS_CONSUMER_EVIDENCE", "")
+ if (!nzchar(output)) return(invisible(NULL))
+ output <- file.path(output, backend, name)
+ dir.create(output, recursive = TRUE, showWarnings = FALSE)
+ utils::write.csv(report, file.path(output, "comparison.csv"), row.names = FALSE)
+ file.copy(candidate$state, file.path(output, "candidate.RData"), overwrite = TRUE)
+ file.copy(reference$state, file.path(output, "reference.RData"), overwrite = TRUE)
+ file.copy(candidate$sql, file.path(output, "candidate.sql"), overwrite = TRUE)
+ file.copy(reference$sql, file.path(output, "reference.sql"), overwrite = TRUE)
+ invisible(NULL)
+}
diff --git a/tests/testthat/test-consumer-integration.R b/tests/testthat/test-consumer-integration.R
new file mode 100644
index 0000000..a5d82a7
--- /dev/null
+++ b/tests/testthat/test-consumer-integration.R
@@ -0,0 +1,94 @@
+check_consumer_contract <- function(backend, test_env = parent.frame()) {
+ withr::local_options(list(lifecycle_verbosity = "quiet"), .local_envir = test_env)
+ conn <- consumer_fixture_database(backend, test_env)
+ had_connection <- exists("con", envir = .GlobalEnv, inherits = FALSE)
+ if (had_connection) previous_connection <- get("con", envir = .GlobalEnv)
+ assign("con", conn, envir = .GlobalEnv)
+ withr::defer({
+ if (had_connection) assign("con", previous_connection, envir = .GlobalEnv) else
+ rm("con", envir = .GlobalEnv)
+ }, envir = test_env)
+ scenarios <- list(
+ state = list(disease = "A90", fail_state = FALSE, failed_cities = numeric()),
+ recovery = list(disease = "A90", fail_state = TRUE, failed_cities = numeric()),
+ isolation = list(disease = "A90", fail_state = TRUE, failed_cities = 3303302),
+ chikungunya = list(disease = "A92.0", fail_state = FALSE, failed_cities = numeric()),
+ zika = list(disease = "A92.8", fail_state = FALSE, failed_cities = numeric())
+ )
+ directory <- withr::local_tempdir(.local_envir = test_env)
+ for (name in names(scenarios)) {
+ scenario <- scenarios[[name]]
+ make <- function(reference) load_pinned_consumer(conn, reference,
+ scenario$fail_state, scenario$failed_cities)
+ candidate <- make(FALSE)
+ reference <- make(TRUE)
+ run <- function(consumer) consumer_known_warnings(consumer$run_disease_pipeline(
+ c(3304557, 3303302), scenario$disease, "none", name, "RJ"
+ ))
+ observed <- run(candidate)
+ expected <- run(reference)
+ observed_publication <- consumer_publication(candidate, observed,
+ file.path(directory, name, "candidate"), scenario$disease)
+ expected_publication <- consumer_publication(reference, expected,
+ file.path(directory, name, "reference"), scenario$disease)
+ report <- compare_epidemiological_frames(expected_publication$history,
+ observed_publication$history)
+ expect_true(all(report$status == "match"), info = paste(backend, name))
+ data_report <- compare_epidemiological_frames(expected_publication$data,
+ observed_publication$data)
+ expect_true(all(data_report$status == "match"), info = paste(backend, name, "RData"))
+ expect_true(file.exists(observed_publication$sql))
+ expect_named(observed_publication$decoded, names(expected_publication$decoded))
+ if (scenario$fail_state) expect_true(any(grepl("fallback", candidate$events)))
+ if (length(scenario$failed_cities)) {
+ expect_false(any(observed$restab$municipio_geocodigo %in% scenario$failed_cities))
+ }
+ key <- switch(scenario$disease, A90 = "alert_dengue", A92.0 = "alert_chik",
+ A92.8 = "alert_zika")
+ table <- consumer_history_table(conn, observed$restab, key)
+ suppressMessages(write_alerta(observed$restab, datasource = conn))
+ suppressMessages(write_alerta(observed$restab, datasource = conn))
+ stored <- consumer_ordered_rows(DBI::dbReadTable(conn, table))
+ physical <- consumer_ordered_rows(consumer_physical_history(observed$restab))
+ expect_true(all(compare_epidemiological_frames(physical, stored)$status == "match"))
+ if (backend == "postgres") {
+ for (sql in c(expected_publication$sql, observed_publication$sql)) {
+ DBI::dbExecute(conn, paste("DELETE FROM", DBI::dbQuoteIdentifier(conn, table)))
+ DBI::dbExecute(conn, paste(readLines(sql), collapse = "\n"), immediate = TRUE)
+ replayed <- consumer_ordered_rows(DBI::dbReadTable(conn, table))
+ expect_true(all(compare_epidemiological_frames(physical, replayed)$status == "match"),
+ info = paste(backend, name, basename(dirname(sql))))
+ }
+ }
+ record_consumer_evidence(backend, name, report, observed_publication,
+ expected_publication)
+ }
+ failed <- load_pinned_consumer(conn, fail_state = TRUE,
+ failed_cities = c(3304557, 3303302))
+ expect_error(failed$run_disease_pipeline(c(3304557, 3303302), "A90", "none", "dengue", "RJ"),
+ "All municipality executions failed")
+}
+
+test_that("pinned consumer preserves state, recovery and artifacts on SQLite", {
+ check_consumer_contract("sqlite", environment())
+})
+
+test_that("pinned consumer replays reference and candidate SQL on PostgreSQL", {
+ check_consumer_contract("postgres", environment())
+})
+
+test_that("SQL export retains numeric precision instead of formatting a character matrix", {
+ snapshots <- epidemiological_snapshots(.reference_root, "dengue")
+ history <- snapshots$candidate$history[1, ]
+ history$p_rt1 <- 0.12345678912345
+ sql_file <- withr::local_tempfile()
+ suppressMessages(write_alerta(history, writetofile = TRUE, arq = sql_file))
+ sql <- readLines(sql_file)
+ header <- sub("^.*?\\((.*?)\\) VALUES.*$", "\\1", sql, perl = TRUE)
+ columns <- gsub('"', "", strsplit(header, ", ", fixed = TRUE)[[1]], fixed = TRUE)
+ values <- sub("^.*?\\) VALUES \\((.*?)\\) ON CONFLICT.*$", "\\1", sql, perl = TRUE)
+ values <- strsplit(values, ", ", fixed = TRUE)[[1]]
+ value <- gsub("^'|'$", "", values[match("p_rt1", columns)])
+ expect_equal(as.numeric(value), history$p_rt1,
+ tolerance = 1e-12)
+})
diff --git a/tests/testthat/test-epidemiological-equivalence.R b/tests/testthat/test-epidemiological-equivalence.R
index 91e6e2a..621ddce 100644
--- a/tests/testthat/test-epidemiological-equivalence.R
+++ b/tests/testthat/test-epidemiological-equivalence.R
@@ -27,4 +27,6 @@ test_that("comparison fails on numerical, missingness and identity changes", {
report <- compare_epidemiological_frames(data, changed)
expect_setequal(report$metric[report$status == "mismatch"], c("casos", "Rt", "id"))
expect_error(compare_epidemiological_frames(data, changed[-1, ]), "cardinality")
+ expect_true(all(compare_epidemiological_frames(data, data[2:1, ])$status == "match"))
+ expect_error(compare_epidemiological_frames(data, data[c(1, 1), ]), "keys.*unique")
})
diff --git a/tests/testthat/test-inla-consumer.R b/tests/testthat/test-inla-consumer.R
new file mode 100644
index 0000000..8638d65
--- /dev/null
+++ b/tests/testthat/test-inla-consumer.R
@@ -0,0 +1,46 @@
+test_that("real Bayesian consumer fallback isolates failures and preserves artifacts", {
+ inla_test_protocol()
+ fixture <- inla_validation_fixture(.inla_root, diseases = "A90")
+ consumer <- new.env(parent = asNamespace("AlertTools"))
+ manifest <- utils::read.csv(file.path(.inla_root,
+ "tests/reference/consumer-27a03f26/manifest.csv"))
+ files <- file.path(.inla_root, "tests/reference/consumer-27a03f26", manifest$file)
+ expect_identical(reference_snapshot_md5(files), manifest$md5)
+ sys.source(file.path(.inla_root, "tests/reference/consumer-27a03f26/functions.R"), consumer)
+ consumer$log_msg <- function(...) invisible(NULL)
+ consumer$report_epiweek <- fixture$report_week
+ consumer$window_weeks <- 200
+ consumer$report_end_date <- epiweek_start(fixture$report_week) + 6
+ fail_state <- TRUE
+ failed_cities <- numeric()
+ consumer$tabela_historico <- function(...) tabela_historico(..., versao = as.Date("2026-10-29"))
+ consumer$pipe_infodengue <- function(cities, ...) {
+ if ((fail_state && length(cities) > 1L) || any(cities %in% failed_cities)) {
+ stop("Injected failure before a municipality fit")
+ }
+ selected <- fixture
+ selected$cases <- fixture$cases[fixture$cases$cidade %in% cities, ]
+ selected$climate <- fixture$climate[fixture$climate$geocodigo %in% cities, ]
+ selected$parameters <- fixture$parameters[fixture$parameters$municipio_geocodigo %in% cities, ]
+ selected$case_records <- fixture$case_records[
+ fixture$case_records$municipio_geocodigo %in% cities, ]
+ AlertTools:::.as_legacy_alert_objects(run_inla_fixture(selected))
+ }
+ cities <- sort(unique(fixture$cases$cidade))
+ run <- function() consumer$run_disease_pipeline(cities, "A90", "bayesian", "dengue", "RJ")
+ res <- run()
+ expect_setequal(res$restab$municipio_geocodigo, cities)
+ expect_true(any(res$restab$casos_est != res$restab$casos))
+ directory <- withr::local_tempdir()
+ save(res, file = file.path(directory, "state.RData"))
+ expect_identical(consumer$load_state_result(file.path(directory, "state.RData")), res)
+ write_alerta(res$restab, writetofile = TRUE, arq = file.path(directory, "state.sql"))
+ expect_true(file.exists(file.path(directory, "state.sql")))
+ failed_cities <- cities[[1L]]
+ partial <- run()
+ expect_setequal(partial$restab$municipio_geocodigo, cities[-1L])
+ failed_cities <- cities
+ expect_error(run(), "All municipality executions failed")
+ evidence <- Sys.getenv("ALERTTOOLS_INLA_EVIDENCE")
+ if (nzchar(evidence)) file.copy(list.files(directory, full.names = TRUE), evidence, overwrite = TRUE)
+})
diff --git a/tools/prepare-consumer-reference.R b/tools/prepare-consumer-reference.R
new file mode 100644
index 0000000..3fb7ca8
--- /dev/null
+++ b/tools/prepare-consumer-reference.R
@@ -0,0 +1,42 @@
+# Input is the raw main_BR.R from the pinned consumer revision, downloaded read-only.
+args <- commandArgs(trailingOnly = TRUE)
+source("tests/reference/comparison.R", local = TRUE)
+if (length(args) != 1L) stop("Usage: Rscript tools/prepare-consumer-reference.R main_BR.R")
+blob <- system2("git", c("hash-object", shQuote(args[[1]])), stdout = TRUE)
+stopifnot(identical(blob, "863937b5b77389c5341a103522bb59c8a75d5789"))
+original <- as.list(parse(args[[1]], keep.source = FALSE))
+names <- c("safe_gc", "combine_ale_parts", "run_city_pipeline",
+ "run_disease_pipeline_by_city", "run_disease_pipeline", "load_state_result",
+ "append_part", "normalize_restab", "normalize_ale", "bind_parts", "cap_max")
+functions <- Filter(function(node) {
+ is.call(node) && identical(node[[1]], as.name("<-")) && is.symbol(node[[2]]) &&
+ as.character(node[[2]]) %in% names && is.call(node[[3]]) &&
+ identical(node[[3]][[1]], as.name("function"))
+}, original)
+stopifnot(setequal(vapply(functions, function(node) as.character(node[[2]]), ""), names))
+publication <- Filter(function(node) {
+ is.call(node) && identical(node[[1]], as.name("if")) &&
+ any(vapply(c("restab_den", "restab_chik", "restab_zika"), function(name) {
+ identical(node[[2]], parse(text = paste0("!is.null(", name, ")"))[[1]])
+ }, logical(1)))
+}, original)
+stopifnot(length(publication) == 3L)
+destination <- "tests/reference/consumer-27a03f26"
+dir.create(destination, recursive = TRUE, showWarnings = FALSE)
+write <- function(nodes, name) {
+ path <- file.path(destination, name)
+ lines <- c("# Unmodified expressions from AlertaDengueAnalise/main/main_BR.R",
+ "# Commit 27a03f26a9bf366597ef135e7da8d2f620ea9a8e",
+ unlist(lapply(nodes, deparse, width.cutoff = 100)))
+ writeLines(sub("[[:blank:]]+$", "", lines), path)
+ stopifnot(identical(as.list(parse(path, keep.source = FALSE)), nodes))
+}
+write(functions, "functions.R")
+write(publication, "publication.R")
+files <- c("functions.R", "publication.R")
+utils::write.csv(data.frame(file = files,
+ consumer_commit = "27a03f26a9bf366597ef135e7da8d2f620ea9a8e",
+ source = "main/main_BR.R", source_git_blob = blob,
+ approved_alerttools = "e460b3b8c15ab28e8755f482d576cf7280803b34",
+ md5 = reference_snapshot_md5(file.path(destination, files))),
+ file.path(destination, "manifest.csv"), row.names = FALSE)
diff --git a/tools/prepare-epidemiological-reference.R b/tools/prepare-epidemiological-reference.R
index 109075a..ce23c1d 100644
--- a/tools/prepare-epidemiological-reference.R
+++ b/tools/prepare-epidemiological-reference.R
@@ -5,7 +5,8 @@ source("tests/reference/comparison.R", local = TRUE)
destination <- "tests/reference/e460b3b8"
dir.create(destination, recursive = TRUE, showWarnings = FALSE)
selected <- list(
- "R/alert_functions.R" = c("setCriteria", "fouralert", "calc.alerta", "tabela_historico"),
+ "R/alert_functions.R" = c("setCriteria", "fouralert", "calc.alerta", "tabela_historico",
+ "write_alerta"),
"R/Rt_functions.R" = c("Rt", "betaconf", "ll"),
"R/adjust_incidence_functions.R" = c("adjustIncidence", "bayesnowcasting"),
"R/nowcasting_fun.R" = c("ff", "gg", "nowcasting", "nowcast.INLA"),
diff --git a/tools/run-inla-integration.R b/tools/run-inla-integration.R
index b1a9163..3a56e87 100644
--- a/tools/run-inla-integration.R
+++ b/tools/run-inla-integration.R
@@ -16,8 +16,8 @@ results <- devtools::test(filter = "inla-(integration|reference|consumer)", stop
summary <- as.data.frame(results)
utils::write.csv(summary[vapply(summary, is.atomic, logical(1))],
file.path(output, "test-results.csv"), row.names = FALSE)
-if (nrow(summary) != 3L || any(summary$skipped) ||
+if (nrow(summary) != 4L || any(summary$skipped) ||
any(summary$failed > 0 | summary$error | summary$warning > 0)) {
- stop("Real INLA integration did not pass all three required scenarios; inspect the evidence")
+ stop("Real INLA integration did not pass all four required scenarios; inspect the evidence")
}
cat("Real INLA integration passed: all required scenarios executed.\n")
diff --git a/tools/run-postgres-integration.R b/tools/run-postgres-integration.R
new file mode 100644
index 0000000..4d0d5f6
--- /dev/null
+++ b/tools/run-postgres-integration.R
@@ -0,0 +1,29 @@
+args <- commandArgs(trailingOnly = TRUE)
+output <- if (length(args)) args[[1]] else "consumer-evidence"
+if (!identical(Sys.getenv("ALERTTOOLS_TEST_POSTGRES"), "true") ||
+ !identical(Sys.getenv("PGDATABASE"), "alerttools_test")) {
+ stop("Requires the disposable alerttools_test PostgreSQL database and explicit test opt-in.")
+}
+if (!requireNamespace("RPostgres", quietly = TRUE)) stop("RPostgres must be installed.")
+dir.create(output, recursive = TRUE, showWarnings = FALSE)
+Sys.setenv(ALERTTOOLS_CONSUMER_EVIDENCE = normalizePath(output))
+results <- devtools::test(stop_on_failure = FALSE)
+summary <- as.data.frame(results)
+atomic <- vapply(summary, is.atomic, logical(1))
+utils::write.csv(summary[atomic], file.path(output, "test-results.csv"), row.names = FALSE)
+sources <- list.files("R", pattern = "\\.R$", full.names = TRUE)
+utils::write.csv(data.frame(file = sources, md5 = unname(tools::md5sum(sources))),
+ file.path(output, "candidate-sources.csv"), row.names = FALSE)
+file.copy("tests/reference/consumer-27a03f26/manifest.csv",
+ file.path(output, "consumer-manifest.csv"), overwrite = TRUE)
+file.copy("tests/reference/e460b3b8/manifest.csv",
+ file.path(output, "reference-manifest.csv"), overwrite = TRUE)
+writeLines(sub("[[:blank:]]+$", "", capture.output(sessionInfo())),
+ file.path(output, "environment.txt"))
+postgres <- grepl("consumer.*PostgreSQL", summary$test)
+if (sum(postgres) != 1L || any(summary$skipped[postgres])) {
+ stop("The pinned consumer PostgreSQL contract was not executed.")
+}
+if (any(summary$failed > 0L | summary$error | summary$warning > 0L)) {
+ stop("Package or consumer integration checks failed; see the uploaded evidence.")
+}