# ADR-048 — Versionamento, consolidação e revogação de legislação

| Campo | Valor |
|---|---|
| **Status** | Aceito (2026-10-23) |
| **Data** | 2026-10-23 |
| **Plano de origem** | `wiki/implementation-phases/P10-legislacao.md` |
| **Relacionadas** | ADR-001, ADR-007, ADR-012, ADR-017, ADR-018, ADR-027, ADR-035, ADR-042 |

## Contexto

Legislação municipal não é um repositório de PDFs. O cidadão precisa da versão vigente, da versão
original e do histórico de alterações/revogações; a administração precisa provar o que estava em
vigor em cada data. O legado tratava o ato como arquivo, sem linha do tempo, e a busca só encontrava
metadados.

A solução não pode virar um editor jurídico completo nem um Git de textos: precisa de rastreabilidade
suficiente para transparência, com URL estável, sem sobrescrever o passado.

## Decisão

1. **Versão é imutável.** Cada publicação de norma cria uma versão (`norma_versoes`) com texto AST
   (`jsonb`), metadados, checksum, `publicado_em`, ator e vínculo com a versão anterior. Editar
   texto publicado **não** sobrescreve: cria nova versão ou errata.
2. **Norma tem identidade estável.** `normas` guarda `slug`/número/ano/tipo/órgão e aponta para a
   versão vigente; a URL canônica é estável e a versão antiga continua acessível por URL própria.
3. **Consolidação é derivada.** Uma versão consolidada é gerada a partir da versão original + 
   alterações aplicáveis, com links para cada alteração; não substitui o texto original. A
   consolidação é uma **nova versão** com `tipo=consolidada` e `base_version_id`.
4. **Revogação é metadado explícito.** `revogada_em`, `revogada_por` (norma/ato) e motivo; a norma
   revogada permanece consultável e deixa de ser “vigente”. Nunca delete físico.
5. **Alteração é relação.** `norma_alteracoes` liga norma alteradora e alterada, com tipo
   (`alteracao|revogacao|retificacao|consolidacao`), artigo/dispositivo e data. Não há parsing
   automático de “revoga o art. X”; o operador registra o vínculo.
6. **URL e SEO.** URL canônica por norma/versão; `canonical` e `hreflang` por locale; sitemap aceita
   apenas portal; `301` curado para URLs antigas; preview de rascunho assinado e `noindex`.
7. **Busca e export.** Texto AST derivado para FTS; `DatasetSource` publica a relação de normas
   (metadados + URL, não HTML) via `OpenData`; CSV/JSON/XML determinísticos. PDF é apresentação, não
   a única fonte.
8. **Importação idempotente.** CSV/planilha operacional usa o importador (P9) com chave
   `tipo+numero+ano+versao`, dry-run e relatório; sem ETL de legado (ADR-042).
9. **Auditoria.** Toda criação/versão/consolidação/revogação gera `AuditEntry` com before/after
   redigido; o texto integral não entra na trilha.

## Justificativa — alternativas descartadas

| Alternativa | Por que não |
|---|---|
| Um registro mutável + auditoria | Não prova o texto vigente em uma data; auditoria não é versionamento editorial. |
| Git/diff/merge de textos | Complexidade e semântica jurídica; não é necessário para consulta/transparência. |
| Só PDF | Não é dado estruturado, não indexa texto nem permite consolidação. |
| Sobrescrever o texto e guardar “histórico” em HTML | Viola ADR-017/028 e dificulta busca/consolidação. |
| OCR de PDFs | Fora do padrão; texto entra pelo CMS/importador. |

## Consequências

**Positivas**
- Histórico auditável, URL estável e consulta por data.
- Consolidação explícita, sem sobrescrever o original.
- Busca e dados abertos usam o texto estruturado.

**Custos / riscos**
- O operador precisa registrar vínculos/consolidações; a UI deve ser simples e validada.
- Muitas versões exigem índices e paginação por `(norma_id, publicado_em, id)`.
- A semântica de “vigente” e “consolidada” precisa de validação jurídica local.

## Exemplo mínimo

```text
norma 123/2024
  versão 1 (original, 2024-03-01)  ── alterada por 45/2025
  versão 2 (consolidada, 2025-02-10, base=v1)
  revogada_em 2026-01-01 por 7/2026
```

## Verificação

- Publicar versão nova não altera a anterior; URL antiga continua 200.
- Consolidada aponta para original e alterações; texto original intacto.
- Revogada sai de “vigente”, mas continua consultável e no histórico.
- Busca encontra texto da versão vigente; export não contém HTML.
- Importação repetida não duplica (`tipo+numero+ano+versao`).
- `make check` 2×; cobertura ≥90%; PHPStan max 0.

## Referências

- `wiki/implementation-phases/P10-legislacao.md`, `P9-servicos-plataforma.md`;
- `wiki/adr/ADR-017-migrations-seguras-dados-desacoplados.md`,
  `ADR-018-dados-abertos.md`, `ADR-028-editor-rico-tiptap.md`.
