# Review — EGT-50 r4: Heyet 132 Bulgularının Kapanışı — 2026-07-26

> **Review type:** re-review (r3'ün R3-1…R3-7 bulguları + 2 açık sorusunun kapanış doğrulaması; spec v1.9.1 · plan v2.4.2)
> **Previous review:** `docs/reviews/review-egt50-ofis-backoffice-2026-07-26-r3.md` (REJECTED) · zincir: ilk tur → r2 → r3
> **Upstream document(s) read:** r3 bulgu listesi (birincil ölçüt) · `CLAUDE.md` kırmızı çizgiler
> **Other cross-referenced documents:** `git diff b11fd48..9ee319c` (tam revizyon diff'i) · `omurga-spec.md` v1.9.1 (başlık + revizyon notu) · `omurga-plan.md` (başlık, pin, 2.4.2 girdisi — satır doğrulamalı) · chunk2 §2.5 muafiyet tablosu (satır doğrulamalı) · chunk3 §3.6.1 B-1…B-8 + kriterler 17b/17b-2/17b-3/19 · chunk9 §9.5 S-11…S-15 · `docs/issues.md` · `config/audit.php`
> **Stage locks in effect:** F-2/F-3 Sets kararları, L-1a/L-1b, üç majörün (R2-1/R2-2/R2-3) kapanışları — yeniden açılmadı. R3-7'nin **çözümü** bilinçli olarak chunk8 turunda; bu turda yalnız kaydının yeterliliği ölçüldü. Chunk 1/2 implementasyonları APPROVED; chunk3 implementasyonu ve `backoffice_users` kapsam dışı.

---

## Bulgu Kapanış Matrisi

| r3 bulgusu | Durum | Kanıt |
|---|---|---|
| **R3-1** (orta) — sabit `'off'` iç içe kullanımda dış scope'u bayraksızlaştırırdı | ✓ kapandı | **B-5**: önceki değer okunur → `'on'` → `finally`'de önceki değer geri yüklenir; sessiz-eksik-sonuç gerekçesi metinde. **B-5a** sözleşmesi: yalnız tam `'on'` → true; `NULL`/`''` (deney 6)/`'off'` → false. **17b-3** iç içe probu *"sabit `'off'` yazan implementasyon bu testte kırılır"* — yanlış implementasyonu testte görünür kılıyor; 17b'ye üç-durum sözleşme testi eklendi |
| **R3-2** (orta) — chunk2 muafiyet tablosu B-6 ile çelişiyordu | ✓ kapandı | `omurga-plan_chunk2.md` §2.5 SELECT satırına adlandırılmış istisna işlendi: yalnız `AuditReadScope`, yalnız `audit_writes`/`audit_access`, bileşene tanınır, `audit_usage` kapsam dışı, chunk3 §3.6.1 B-6 çapraz referanslı. Kanun tek yerde |
| **R3-3** (orta) — S-12'de `config/` yoktu; kriter 19 eski tarifteydi | ✓ kapandı | S-12 allowlist'ine `config/audit.php` gerekçesiyle eklendi (tablo haritası + owen-it `implementation`); kriter 19 S-12 diline çekildi ve *"kriter 'yalnız `App\Queries\Audit\**`' demez"* açıklaması eklendi |
| **R3-4** (minör) — S-13'ün Inertia tarifi yol değildi | ✓ kapandı | Dört yol adlandırıldı (`app/Filament/**` · `app/Http/Controllers/**` · `app/Http/Resources/**` · `resources/js/**`), aranan altı dizge tek tek sayıldı; S-14 aynı yollara + `routes/**`'a bağlandı ve kendi allowlist'ini aldı |
| **R3-5** (minör) — S-15 "benzeri" mekanik değildi | ✓ kapandı | Yedi dizgelik sonlu liste; "listeye ekleme plan değişikliğidir; listede olmayan varyantı yakalamak taramanın değil review'ın işidir" — meta-kuralla tam uyumlu |
| **R3-6** (minör) — başlıklar geçmişle çelişiyordu | ⚠ kısmen: spec ✓, plan yine kaydı | Spec başlığı **1.9.1** ✓ ve düzeltme notu dürüst ("içerik değişmedi"). Plan başlığı **2.4.1**'e çekildi ama bu turun kendisi **2.4.2** girdisini ekledi (`omurga-plan.md:3` ↔ `:144`) — desen üçüncü kez tekrarladı (→ **R4-1**) |
| **R3-7** (orta) — agregat okuma mekanizması kayıtsızdı | ✓ kaydı yeterli | `docs/issues.md` kalemi: boşluğun tam tarifi (kesin liste, CAgg-RLS, bekçi, G-1), iki muhtemel adres, karar chunk8 turunda, "önceden var olan boşluk" notu. Bu turda istenen buydu |
| **Açık soru 1** — iç içe davranış kararı | ✓ kapandı | Sakla-geri-yükle seçildi; gerekçe ikili ve sağlam: `TenantContext` ile tek semantik + yasak seçilseydi ihlal ancak çalışma zamanında görülürdü, geri yükleme yanlış implementasyonu **testte** (17b-3) yakalıyor |
| **Açık soru 2** — R3-7'nin adresi | ✓ kapandı | İki seçenek kayıtlı, karar chunk8'e bırakıldı — chunk8'in okuma deseni elde olmadan karar vermeme tercihi doğru |

---

## ✅ What works

- **B-5 + B-5a + 17b-3 üçlüsü R3-1'i tam kapatıyor — "dıştaki değer hiç kurulmamışsa" sorusu dahil.** Geri yüklenecek önceki değer `NULL` ise `SET LOCAL` ile pratikte `''` yazılır (GUC'a NULL geri yüklenemez); B-5a sözleşmesi `NULL`, `''` ve `'off'` üçünü de false yaptığı için bu temsil farkının **davranışsal karşılığı yoktur** — "off mu, hiç yazmamak mı" ayrımı sözleşme sayesinde önemsizleşir. 17b'nin üç-durum testi sözleşmeyi, 17b-3 restore'u sınıyor; ikisi birlikte ayrımı kapatıyor. (İmplementasyon notu, bulgu değil: restore `set_config('app.audit_read_all', <önceki-veya-''>, true)` biçiminde yazılırsa NULL temsili kendiliğinden çözülür.)
- **R3-2'nin yazımı chunk2'nin dar-muafiyet ilkesini bozmadı** (Sets sorusu 2'nin cevabı: hayır). Tablo hâlâ kesin liste niteliğinde: her satır bileşen adı + tablo adı + yön üçlüsüyle sınırlı; yeni istisna aynı biçimde, tek cümlede, çapraz referanslı. "Muafiyet tabloya değil bileşene" ilkesi iki yönde de (INSERT: üç logger · SELECT: `AuditReadScope`) aynı dille duruyor.
- **Sakla-geri-yükle tercihine verilen gerekçe** ("yasak seçilseydi ihlal yalnız çalışma zamanında görülürdü; geri yükleme yanlış implementasyonu testte görünür kılar") bu projenin test disiplinine tam oturan bir argüman — karar yalnız doğru değil, doğru gerekçeyle kayıtlı.
- **Kriter 19'un yeni metni** S-12 ile aynı dili konuşuyor ve eski dar tarifin `StampAuditBatch`'i ihlalci sayacağını açıklamasında saklıyor — gelecekte kriterin "sadeleştirilmesi" denemesine karşı bağışıklık.
- **S-13/S-14/S-15 artık meta-kuralın istediği biçimde:** yol listesi + dizge listesi + allowlist; S-15'in "listede olmayan varyantı yakalamak review'ın işidir" cümlesi taramanın verdiği güvenin sınırını dürüstçe çiziyor.
- **R3-7 kaydı** tam istenen derinlikte: boşluğun dört bileşeni (kesin liste, CAgg-RLS, bekçi, G-1) tek kalemde, karar sahibi ve zamanı belli.

## ⚠️ Findings & Risks (in-scope for this review type)

**R4-1 (minör) — Plan başlığı yine bir sürüm geride: başlık "2.4.1", bu turun eklediği revizyon girdisi "2.4.2".** `omurga-plan.md:3` ↔ `omurga-plan.md:144`; re-review talebi de "plan v2.4.2" diyor. R2-7 → R3-6 → R4-1: aynı adım üç turdur aynı şekilde kayıyor — başlık, revizyon girdisi eklenirken değil, ondan önceki turun değerine güncelleniyor. Tek satırlık düzeltme; ama desen olarak kayda geçmeli: sürüm damgası ile revizyon girdisi tek adımda atılmadıkça bu kayma tekrarlayacak.

**R4-2 (minör) — S-12/S-13'ün aradığı `AuditWrite` dizgesi `AuditWriter`ın ön ekidir; tarif kelime sınırı istemiyor.** Naif bir `grep AuditWrite`, `AuditWriter`ı da eşler. `AuditWriter.php`'nin kendisi allowlist'te (`app/Support/Audit/**`) ama onu **import eden** meşru dosyalar değil — ör. chunk6'nın `Gate::after` kancası (Y-3 audit'i) veya kimlik doğrulama olaylarını yazan listener, `AuditWriter`ı kullandığı anda allowlist dışı bir dosyada "AuditWrite" eşleşmesi üretir ve tarama yanlış pozitif kırar. Allowlist büyütmek plan değişikliği olduğu için implementer bunu kendi başına düzeltemez — durup sorması gerekir. Tarife tek cümle yeter: dizgeler kelime sınırıyla (`\bAuditWrite\b`) veya FQCN/`::class` biçimiyle aranır.

**R4-3 (minör) — S-11'in "yalnız iki dosya" tarifi, `app.audit_read_all()` fonksiyonunun nerede CREATE edildiğini söylemiyor.** S-11: dizge yalnız `AuditReadScope.php` ve "politikaları kuran migration"da geçer. Fonksiyonun `CREATE FUNCTION`'ı da bu dizgeyi içerir; iki-dosya sınırı ancak fonksiyon **aynı policy migration'ında** tanımlanırsa tutar. Bunu yazan yok — fonksiyonları doğal adresleri olan chunk2'nin context-functions migration'ına koyan bir implementer (`tenant_ids_or_empty` ile yan yana) S-11'i üçüncü dosyayla kırar. Tarife bir ibare yeter: "fonksiyonun CREATE'i de bu migration'dadır" (veya migration deseni allowlist'e `database/migrations/**` olarak yazılır ve daraltma yorumla anlatılır).

## ❓ Open Questions (to be answered before next stage)

Yok. (R3-7'nin chunk8 kararı ve `actor_type`/`backoffice_users` chunk5 kalemi zaten `docs/issues.md`'de sahipli ve zamanlı.)

## ⚠️ Upstream Findings

Yok.

## Previous Findings Status

| # | Durum |
|---|---|
| R3-1 | ✅ Kapandı (B-5 sakla-geri-yükle + B-5a sözleşme + 17b-3) |
| R3-2 | ✅ Kapandı (chunk2 muafiyet tablosu güncel; kanun tek yerde) |
| R3-3 | ✅ Kapandı (`config/audit.php` allowlist'te; kriter 19 S-12 dilinde) |
| R3-4 | ✅ Kapandı (dört yol + altı dizge; S-14 `routes/**` dahil) |
| R3-5 | ✅ Kapandı (yedi dizgelik sonlu liste) |
| R3-6 | ⚠ Spec kapandı; plan başlığı aynı desenle yeniden kaydı (R4-1) |
| R3-7 | ✅ Kaydı yeterli (çözüm bilinçli olarak chunk8 turunda) |

## Verdict: ✅ APPROVED

Dört tur sonunda ilk kez majör ve orta bulgu yok. Üç majör güvenlik/tutarlılık bulgusunun (Y-4, bayrak yaşam döngüsü, feed zemini) kapanışları bu turda da yerinde duruyor; r3'ün yedi bulgusunun altısı tam kapandı, yedincisinin (R3-6) spec yarısı kapandı. Kalan üç bulgu (R4-1/2/3) minördür ve hiçbiri güvenlik desenini, spec–plan tutarlılığını veya kriterlerin ölçülebilirliğini etkilemiyor — üçü de davranış değiştirmeyen, tek cümlelik metin netleştirmesidir. R4-2 ve R4-3, chunk9 implementasyonu sırasında yanlış-pozitif tuzağına dönüşebileceği ve allowlist değişikliği plan turu gerektirdiği için chunk9'dan önce; R4-1 herhangi bir commit'te düzeltilmelidir. Bu üç düzeltme için yeni bir re-review turu gerekli görünmüyor — diff'in bulgularla birebir eşleşmesi yeterli. Belge seti bu haliyle chunk3 implementasyonuna temel olabilir. Son karar kullanıcınındır.
