# 3E Akademi — denetim zinciri delil paketi

Bu paket, sistemin denetim kayıtlarının **sonradan değiştirilmediğini**, 3E'nin uygulama kodu kullanılmadan doğrulamanız için gereken her şeyi taşır.

---

## Paketin içinde ne var

| Dosya | Ne işe yarar |
|---|---|
| `BENIOKU.md` | bu dosya — adım adım ne yapılacağı |
| `muhurler.json` | mühürler: kök, önceki halka, zincir özeti, kural adı, satır aralığı, tanık adresi |
| `dogrula.py` | bağımsız doğrulayıcı; içinde 3E'ye ait hiçbir kütüphane yoktur |
| `sorgular.sql` | aynı hesabı elle yapmak için ham SQL |
| `yaprak-kurali.md` | `sha256-utc-iso-v2` kuralının tam tanımı |
| `tanik.txt` | mühürlerin yayımlandığı dış deponun adresi ve her mührün oradaki karşılığı |

## Paketin içinde ne YOK

⛔ **Denetim satırlarının kendisi.** Bir tane bile.

Satırlar kişisel veri taşır — kimlik numarası, telefon, kimin ne yaptığı. Bir **kök** ise kapsadığı şey hakkında hiçbir şey söylemez: yalnızca 64 karakterlik bir özettir. Bu asimetri, kökleri yayımlamayı hem güvenli hem faydalı kılan şeydir ve bu paketin dışarı çıkabilmesinin sebebidir.

Satırları veritabanından **siz okursunuz**. Biz size veriyi değil, kuralı veririz.

---

## Neye ihtiyacınız var

- Denetim veritabanına **okuma** erişimi (`audit_writes`, `audit_access` tabloları ve `app.` şemasındaki fonksiyonlar).
- `psql` **veya** Python 3.9+.

Python 3.12 ile geliştirildi ve orada sınandı. `dogrula.py` yalnız standart kütüphaneyi kullanır; `psycopg` **isteğe bağlıdır**.

---

## Yol 1 — hiçbir şey kurmadan (önerilen)

Bu yol delil açısından daha güçlüdür: veriyi veritabanından çıkaran şey bizim betiğimiz değil, **sizin kendi `psql`'inizdir**.

```bash
# 1. Yaprakları kendi psql'inizle dışarı alın
psql "$DSN" -At -F $'\t' -f sorgular.sql > satirlar.tsv

# 2. Doğrulayın
python3 dogrula.py --rows satirlar.tsv
```

## Yol 2 — doğrudan veritabanından

```bash
pip install "psycopg[binary]"
python3 dogrula.py --dsn "postgresql://kullanici:parola@sunucu:5432/veritabani"
```

## Beklenen çıktı

```
OK audit_writes 0→412 (2026-08-01)
OK audit_writes 412→800 (2026-08-02)
...

Zincir dogrulandi: 1284 muhur.
```

Uyuşmazlık varsa satır `X` ile başlar ve neyin tutmadığını söyler; çıkış kodu `1` olur.

---

## Yol 3 — betiğe de güvenmeden

`dogrula.py` yüz satırlık bir dosyadır ve okunması beklenir. Ama isterseniz hiç çalıştırmayın:

1. `yaprak-kurali.md`'yi okuyun — bir satırın nasıl tek bir metne çevrildiği orada yazılıdır.
2. `sorgular.sql`'deki 3. bölümü izleyin: özetleri alın, ikişer ikişer katlayın, kökü bulun.
3. Bulduğunuz kökü `muhurler.json`'daki `merkle_root` ile karşılaştırın.

Kuralın kendisi **veritabanında** tanımlıdır ve tanımı da okunabilir:

```
\df+ app.audit_leaf_line
\df+ app.audit_batch_merkle_root
```

Bu belge ile veritabanındaki tanım çelişirse, **veritabanındaki esastır**.

---

## Doğrulama neyi kanıtlar

**Kanıtlar:** mühürlenmiş satırların o mühürden sonra değiştirilmediğini. Bir satırın tek bir alanını değiştirmek o kümenin kökünü ve ondan sonraki bütün zincir halkalarını değiştirir — bozulma yerel kalamaz.

**Kanıtlamaz:** zincirin **ne zaman** kurulduğunu. Buradaki hiçbir hesap, geçen mart mühürlenmiş bir zincirle bu sabah baştan üretilmiş birini ayırt edemez.

Bunu söyleyen şey **dış tanıktır**. `tanik.txt` deponun adresini verir; depo herkese açıktır, geçmişi yeniden yazmaya (force-push) ve silmeye kapalıdır. Mühürler oraya, alındıkları gün yayımlanır. Satırları değiştirip yeniden mühürlemek yerelde kusursuz bir zincir bırakır — itiraz eden tek şey o depodaki kopyadır.

Bu yüzden doğrulamanın iki yarısı vardır ve ikisini de yapmanız beklenir:

1. `dogrula.py` — satırlar mühürlere uyuyor mu?
2. `tanik.txt` — mühürler, yayımlandıkları hâlleriyle aynı mı?

---

## Bir uyuşmazlık bulursanız

Betik bir mührü `X` ile işaretlerse, bu şu üçünden biridir ve hangisi olduğu üç kökü yan yana koyarak anlaşılır:

| Kaydedilen kök | Yeniden hesaplanan | Tanıktaki | Anlamı |
|---|---|---|---|
| A | **B** | A | satırlar değişmiş |
| A | A | **B** | mühür değişmiş |
| A | **B** | **B** | satırlar ve mühür birlikte değişmiş (yeniden mühürleme) |

Üçüncü durum, dış tanığın var olma sebebidir.

---

## Kural değişirse

Her mühür, hangi kurala göre alındığını `hash_algorithm` alanında taşır. Bu paket `sha256-utc-iso-v2` kuralını anlatır. Başka bir ad taşıyan bir mühür bu kurala göre hesaplanamaz ve doğrulayıcı onu **"doğrulanamadı"** olarak raporlar — **"kırık" olarak değil.** İkisi farklı şeylerdir ve karıştırılmaları, kural değişikliğini bir bozulma gibi göstermek olurdu.
