# Versionamento Temporal do Grafo

**Documento:** `grafo/05-versionamento-temporal.md`  
**Versão:** 1.0.0

---

## 1. Problema

Relacionamentos públicos **nascem e morrem** (sócio sai, contrato encerra, sanção é levantada). Análises retrospectivas (“como era o grafo em T?”) e Watch (“o que mudou desde T0?”) exigem temporalidade de primeira classe — sem reescrever o passado.

---

## 2. Modelo temporal adotado: *Valid Time* + *Transaction Time* (bitemporal leve)

| Eixo | Campo | Significado |
|------|-------|-------------|
| **Valid time** | `valid_from`, `valid_to` | Período em que o fato foi verdadeiro no mundo (conforme fonte) |
| **Transaction time** | `projected_at`, `superseded_at` | Quando o grafo Mud Sentinel passou a representar esse estado |

**Justificativa:**  
- Valid time responde análises “as of”.  
- Transaction time responde auditoria “o que a plataforma sabia quando o analista exportou?”.

Quando a fonte não traz vigência clara: `valid_from = observed_on`, `valid_to = null`, `precision = day|month|unknown`.

---

## 3. Estratégias de representação (conceitual)

### 3.1 Arestas versionadas (padrão)

Cada mudança material cria **nova aresta** (novo `edge_id`) ou nova versão encadeada:

```text
OWNS e1: A→B  valid[2019-01-01, 2023-06-30]  projected_at=…
OWNS e2: A→B  valid[2023-07-01, ∞)           projected_at=…
e1.superseded_by = e2
```

**Proibido:** update-in-place apagando vigência anterior.

### 3.2 Nós de fato imutáveis + arestas de estado

Para `CONTRACT`, status muda via propriedades versionadas ou sub-nós `CONTRACT_STATE` — preferir **eventos de status** na Timeline + propriedade atual *derivada* no nó live.

### 3.3 Snapshots de subgrafo (pontuais)

Para Evidence/Export: materializar `GraphView` com lista de `edge_id`s + `as_of` + hashes → imutável.

---

## 4. Consulta `as_of`

**Definição:** nó/aresta visível em `T` see

```text
valid_from ≤ T AND (valid_to IS NULL OR valid_to > T)
AND projected_at ≤ T_tx   # se modo “o que sabíamos”
AND layer ∈ filter
```

Dois modos de produto:

| Modo | Uso |
|------|-----|
| `WORLD_AS_OF` | Só valid time (verdade alegada do mundo) |
| `PLATFORM_AS_OF` | Valid ∩ transaction (reprodutibilidade de dossiê) |

Exports de Case devem gravar **ambos** os timestamps.

---

## 5. Diff temporal / Watch

**Algoritmo conceitual `GraphDiff(T0, T1)`:**

1. Arestas com `valid` intersectando (T0,T1] e não (≤T0).
2. Classificar: `opened`, `closed`, `attribute_changed`.
3. Filtrar por WatchTarget / AlertRule.
4. Emitir Alert com refs de edge_ids.

---

## 6. Granularidade e precisão

| Precision | Exemplo | Regra de UI |
|-----------|---------|-------------|
| `day` | data de assinatura | mostrar data |
| `month` | só mês/ano na fonte | mostrar “≈ AAA-MM” |
| `unknown` | “exercício 2022” | intervalo expandido com bandeira |

Algoritmos de path usam *intersect* de vigências: um path é válido em `T` se **todas** as arestas o forem (política estrita MVP). Política alternativa “quase contemporâneo” (slack δ) é P1 e deve ser rotulada.

---

## 7. Retenção temporal

| Camada | Retenção de versões |
|--------|---------------------|
| L1 factual | Longa (anos) — alinhada a SourceRecord |
| L2 derived | Recomputável; pode compactar históricos antigos |
| L3 AI candidates | Curta se rejeitados; accepted seguem política |
| GraphPath cache | Ephemeral |
| GraphView evidência | Enquanto Case/retenção do Tenant |

**Justificativa:** derivados são baratos de recomputar; fatos observados não.

---

## 8. Merge de Party no tempo

Quando `SAME_AS` / merge ocorre:

1. Redirect de `node_id` surviving.
2. Arestas históricas preservadas com `endpoint_resolved_id`.
3. Diff explica “identidade unificada em TX”.
4. Views antigas continuam resolvíveis via mapa de merge.

---

## 9. Reprocessamento de fonte (correção)

Se SourceRecord S é superseded:

1. Arestas suportadas **somente** por S → `retracted` ou nova versão corretiva.
2. TimelineEvent de correção.
3. IntegritySignals dependentes → withdraw/recompute.
4. Audit de reprocessamento.

Nunca silenciar correção.

---

## 10. Diagrama do ciclo temporal

```text
SourceRecord published
    → project node/edge (projected_at=now, valid_*=from source)
        → as_of queries / expand / path
            → Watch diff → Alert
        → correction/supersede
            → new edge version + retract old
                → recompute L2/L3 + signals
```
