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

> **Review type:** re-review (heyet 130'un 10 bulgusu + 4 açık sorusunun kapanış doğrulaması; spec v1.9 · plan v2.4 · AD-21/AD-23)
> **Previous review:** `docs/reviews/review-egt50-ofis-backoffice-2026-07-26.md` (REJECTED — F-1…F-10)
> **Upstream document(s) read:** önceki turun bulgu listesi (birincil ölçüt) · Sets'in F-2/F-3 kararları (re-review talebi + `docs/issues.md`) · `CLAUDE.md` kırmızı çizgiler · AD-09/AD-21/AD-23 güncel metin
> **Other cross-referenced documents:** `git diff 04bca0d..2c309ce` (tam revizyon diff'i) · `omurga-spec.md` v1.9 (§4.1, §6 Y-4, T-4, §7.5, §13, §14, revizyon geçmişi) · `omurga-plan.md` v2.4 · chunk3 (§3.1, §3.6, §3.6.1, §3.10) · chunk8 (§8.5, §8.9) · chunk9 (§9.5, §9.8) · chunk2 (§2.5, §2.5.1, §2.8.1, deney 6/11 — değişmedi, çapraz doğrulama) · `docs/issues.md` · `docs/claude/heyet.md`
> **Stage locks in effect:** F-2 ve F-3 **Sets kararıyla** kapandı ve `docs/issues.md`'ye işlendi — kararların kendisi yeniden tartışılmaz; bu turda yalnız **yazımlarının** tutarlılığı ölçüldü. Chunk 1/2 implementasyonları APPROVED; chunk2 mekanizmaları bu turda yalnız çapraz referans olarak kullanıldı. `backoffice_users` ve chunk3 implementasyonu kapsam dışı.

---

## Bulgu Kapanış Matrisi

| Önceki bulgu | Durum | Kanıt |
|---|---|---|
| **F-1** — spec'te "Aktivite logu" kalıntısı | ✓ kapandı | §13 satırı "Kullanım logu"na çevrildi; §14/8 yeniden yazıldı: özne kullanım logu, ekran **backoffice**, *"yazma olayları ve erişim logu bu ayardan etkilenmez — onlar silinmez"* (açık soru 4 dahil). Spec'te kalan "aktivite" geçişleri yalnız revizyon geçmişinde (tarihsel) |
| **F-2** — "son aktif" ↔ L-1 çelişkisi | ✓ kapandı (Sets kararı) | **L-1a** (`omurga-spec.md:246`): adlandırılmış tek istisna, dört dışlama sayılmış (giriş geçmişi/oturum listesi/giriş sayısı/süre), "başka alan eklenemez". L-1 metni "ne zaman giriş yaptığı" → "giriş geçmişi" olarak daraltıldı (damga ile çelişki metin düzeyinde de giderildi). AD-21'e online rozeti farkının gerekçesi yazıldı (sürekli yüzey ↔ tek zaman noktası). chunk8 `:61` uyarı + kriter 9b. Karar `docs/issues.md`'de |
| **F-3** — giriş/çıkış olaylarının feed durumu | ✓ kapandı (Sets kararı) | **L-1b** + AD-21 paragrafı + chunk3 §3.6 "Kimlik doğrulama olayları feed'de kalır" + kriter 15b. Heyetin gerekçesinin reddi açıkça kayıtlı (`docs/issues.md`). Koruma dört katman: kırmızı çizgi 17 (CLAUDE.md) · L-1b "üretmez" · S-2 taraması · 15b dönüş testi |
| **F-4** — §3.6.1 kurulamıyordu | ⚠ desen düzeldi, iki mekanizma boşluğu kaldı | Numaralandırma bırakıldı, bağlam beyanı (`app.audit_read_all`) + B-1…B-4 + 17b–17e; eski yolun neden kurulamadığı da metne yazıldı (`omurga-plan_chunk3.md:184`). Kalan: bayrağın yaşam döngüsü (**R2-2**), feed'in TenantContext entegrasyonu (**R2-3**), S-4 deseni (**R2-6**) |
| **F-5** — "tek istisna" enflasyonu | ✓ kapandı | L-4 → "T-4'ün denetim kayıtlarına uygulanışı, yeni yetki değil"; T-4'e sınır cümlesi (`omurga-spec.md:117`); AD-21 (`mimari-kararlar.md:207`) ve chunk3 §3.6.1 aynı dile çevrildi. Kalan "tek" iddiaları farklı eksenlerde ve meşru (§4.1 bağlamsız-işlem ekseni; S-9 mekanizma ekseni; L-1a kendi istisnasının tekliği) |
| **F-6** — N-4 gerekçesi hatalı, zorlama yok | ✓ gerekçe kapandı; zorlamanın tarifi taranabilir değil | Yeni gerekçe (`omurga-plan_chunk3.md` §3.6) olgusal olarak doğru ve dürüst: satır niteliği ↔ oturum niteliği, ikinci GUC = görünürlük için ikinci bypass anahtarı. "Sınıfın kendisi atlanabilir" itirafı metne girdi; telafi S-12 + kriter 19. Ancak S-12 tarifi mekanik olarak uygulanamaz → **R2-4** |
| **F-7** — chunk9 kesin listesi eksik | ✓ yapısal olarak kapandı | S-11…S-14 `omurga-plan_chunk9.md:90-93`; kriter 7 "on dört kural"; chunk3'ün dört atfı somut maddeye bağlandı (S-11/S-12/S-13/S-14). Ancak S-12 ve S-13'ün tarifleri taranabilirlik testini geçmiyor → **R2-4, R2-5** |
| **F-8** — index güncel değil | ✓ kapandı, iki küçük pürüzle | v2.4 · 26.07.2026; pin v1.9; 2.4 revizyon girdisi eklendi. Pürüzler: **R2-7** |
| **F-9** — AD-23 kural 1 çelişkisi | ✓ AD katmanında kapandı; çelişki spec Y-4'e taşındı | Kural 1 (`mimari-kararlar.md:269`): "Ofis içinde" + adlandırılmış kalıcı istisna; provisioning maddesi "önce gelen adım" iddiasını bıraktı, "süreklilik arz eden muafiyet" dedi. Ancak **spec §6 Y-4 mutlak kaldı** → **R2-1** |
| **F-10** — `actor_type` ↔ spec §3.0 | ✓ kapandı | Üç değer; `participant`'ın neden tür olmadığı spec §3.0 diliyle yazıldı; katılımcı ekranından üretilen olayın `customer_user` yazacağı açık; kriter 15 enum'u şema sorgusuyla sınıyor |

**Açık soruların kapanışı:** (1) `system` feed'de — cevaplandı, gerekçesi sağlam (kişi izlemez; yokluğu "kayıt kendiliğinden değişti" yanılgısı üretir), N-4 ve kriter 15 güncellendi ✓. (2) backoffice aktörü — `docs/issues.md`'ye kalem olarak yazıldı, chunk5'e bağlandı ✓. (3) maliyet — yeni desenle konu dışı, doğru ✓. (4) kriter 8 öznesi — F-1 ile yazıldı ✓.

---

## ✅ What works

- **F-4'ün yeni deseni doğru sınıfta bir çözüm.** Bayrak RLS'i kapatmıyor, politikanın bildiği bir koşul; `FORCE RLS` ve non-superuser rol duruyor; `BYPASSRLS`/`SECURITY DEFINER` yok. Bu, chunk2'nin superuser hikâyesinin tekrarı **değil**: superuser bypass'ı *politikanın hiç değerlendirilmemesi*ydi, bayrak ise *politikanın açık bir şıkkı* — görünür, taranabilir, test edilebilir. B-1…B-4'ün her birinin bir zorlama adresi var (S-4, S-11, 17b–17d) ve 17c'nin kasıtlı-ihlal probu ("bayrağı fixture tabloya taşıyan politika testi kırıyor") tam bu projenin test disiplini.
- **Kabul edilen bedelin açıkça yazılması** (fırlatmayan okuma varyantı → bağlamsız SELECT sessizleşir → bekçi kapatır, 17e) — bedel gizlenmemiş, telafisi adreslenmiş. Bekçi muafiyet tablosunun (chunk2 §2.5) SELECT'i zaten dışlıyor olması iddiayı destekliyor.
- **F-6'nın yeni gerekçesi önceki turun tam tersine dürüst:** "RLS bilemez" savunusu bırakılmış, gerçek trade-off (görünürlük için ikinci bir GUC anahtarı açmama tercihi) yazılmış, üstelik "sınıfın kendisi atlanabilir" zayıflığı metnin kendisi tarafından itiraf edilip taramaya bağlanmış.
- **Sets kararlarının kaydı örnek nitelikte:** `docs/issues.md`'de reddedilen heyet gerekçesi de dahil karar izi tutulmuş; L-1a/L-1b spec'te *adlandırılmış* istisnalar — bir ay sonra "bu neden böyle" sorusunun cevabı aranabilir durumda.
- **L-1a'nın darlığı iyi kurulmuş:** dört dışlama tek tek sayılmış, "eklemek spec değişikliğidir" chunk8'e de yazılmış, kriter 9b negatif yüzeyi ("gösteren alan/uç yok") sınıyor. chunk5/chunk6'da bu alana dokunan bir tanım yok — genişleme ancak bilinçli bir spec turu ile olabilir.
- **F-1/F-10 kapanışları eksiksiz;** kriter 15'in enum'u şema sorgusuyla sınaması ve kriter 8'in "diğer iki sınıf etkilenmez" eklentisi, bulguların ruhunu (yalnız kelimeyi değil, yanlış okumayı düzeltme) karşılıyor.

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

**R2-1 (majör) — Y-4 mutlak kaldı; F-9'un çelişkisi AD'den spec'e taşındı.** AD-23 kural 1 artık "**Ofis içinde** kimse..." diyor ve backoffice provisioning'i adlandırılmış istisna olarak taşıyor (`mimari-kararlar.md:269`). Ancak spec §6 **Y-4** değişmedi: *"Bir kullanıcı **sahip olmadığı bir yetkiyi başkasına veremez**"* (`omurga-spec.md:196`) — niteliksiz ve her iki kimlik alanı için. Backoffice yöneticisi, kendisi ofis yetkisi taşımadan ofis yetkisi atar; Y-4 yazıldığı haliyle bunu yasaklamaya devam ediyor. Ayrıca "Ofis içinde" daraltması sonrası **müşteri tarafındaki** yetki devrinin (U-4/U-5, firma yetkilisinin panel yetkisi vermesi) genel kuralı artık yalnız Y-4'te yaşıyor — yani Y-4 hem genel kural olarak gerekli hem de istisnayı taşımıyor. Sets'in 6. sorusunun cevabı budur: "ofis içinde" kaydı kuralı zayıflatmıyor (genel kural Y-4'te duruyor), ama Y-4'e istisna işlenmediği için belge seti yine iki yöne çekiyor — önceki turdaki F-9'un birebir deseni, bir katman yukarıda.

**R2-2 (majör) — `app.audit_read_all` bayrağının yaşam döngüsü eksik: kurma tanımlı, geri alma tanımsız.** `SET LOCAL` transaction sonuna kadar yaşar; `TenantContext` iç içe semantiği `app.tenant_ids` için daraltma + **`finally` ile geri yükleme** tanımlar (chunk2 §2.5), ama bayrak bu semantiğin parçası değil ve B-1…B-4'ün hiçbiri feed'den çıkışta bayrağın düşürülmesini söylemiyor. Sonuç: Action = transaction sınırı olduğuna göre (chunk2 §2.5 "Action iş birimi"), `BackofficeAuditFeed`'i çağıran bir backoffice Action'ının **aynı transaction içindeki sonraki her audit SELECT'i** bayrağı miras alır — erişim logunun yazılışından sonra koşan başka bir audit sorgusu, hiçbir izin kontrolünden geçmeden çapraz-tenant döner. Kriter 17b yalnız **COMMIT sonrası** düşüşü sınıyor; transaction-içi mirası sınayan kriter yok. Sets'in 1. sorusundaki "bayrak kurulup transaction bitmeden başka bir sorgu koşarsa ne olur" senaryosunun cevabı bugün: *bayrak hâlâ açık* — ve bu davranış hiçbir yerde ne kabul edilmiş ne yasaklanmış.

**R2-3 (majör) — `BackofficeAuditFeed`'in uygulama-katmanı entegrasyonu tanımsız; 17e ve 17b buna yaslanıyor ama zemin yazılmamış.** Bekçi, audit tablolarına SELECT için **aktif `TenantContext`** ister (chunk2 §2.5 muafiyeti yalnız INSERT; 17e bu katmanı "bedeli kapatan katman" ilan ediyor). O halde feed hangi kapsamla `run()` edilir? Seçenekler tanımsız: (a) `run([])` — chunk2 §2.5'te boş dizi semantiği yok ve DB temsili `SET LOCAL app.tenant_ids = ''` olur ki deney 6'ya göre boş string **"bağlam yok"** demektir — aktif-ama-boş bağlam ile bağlamsızlık DB düzeyinde ayırt edilemez; (b) backoffice kimliğinin ortam kapsamı — `ScopeResolver`'ın backoffice kimliği için ne döndürdüğü hiçbir yerde tanımlı değil (chunk2 §2.8.1 ara dönemde ofis kimliğine *boş kapsam + isimli exception* veriyor; chunk6 `TreeScopeResolver` org kapsamı döndürür, "backoffice" diye bir dalı yok). Bu tanımlanmadan kriter 17b/17e'nin testleri kurulamaz; implementer'ın önünde "plan kanundur" rejiminde cevabı olmayan bir soru durur. (Önceki turun F-4'ü *RLS katmanının* kaynağını çözdü; aynı sorunun *uygulama katmanı* yarısı açık kaldı.)

**R2-4 (orta) — S-12'nin tarifi, planın kendi meşru erişimcilerini kırıyor; yazıldığı haliyle taranamaz.** S-12: *"`audit_writes` / `audit_access` üzerinde `App\Queries\Audit\**` dışından sorgu yok"* (`omurga-plan_chunk9.md:91`). Ama planın kendisi bu tabloya o namespace dışından dokunan en az dört meşru bileşen tanımlıyor: `AuditWriter`/`AccessLogger` (INSERT — `app/Support/Audit/`), `App\Models\AuditWrite` (tablo bağlaması), `StampAuditBatch` (damga özeti için **satırları okur** — `app/Jobs/`), append-only arch testleri (`tests/`). "Sorgu"nun kapsamı (yalnız SELECT mi? Eloquent mi, tablo adı geçişi mi?) ve istisna listesi tanımsız — tarama ya bu bileşenlerde kırılır ya da tarifi gevşetilirken asıl hedefi kaçırır. Sets'in 5. sorusunun cevabı S-12 için: **hayır, bu haliyle mekanik değil.**

**R2-5 (orta) — S-13 aynı sınıfta: "iş akışı ekranı" ile "denetim ekranı"nı tarama ayırt edemiyor.** S-13: *"Inertia sayfa/Filament resource veri kaynaklarında `audit_*` tablosu yok"* (`omurga-plan_chunk9.md:92`). Oysa planın meşrulaştırdığı iki ekran tam bu desene uyar: backoffice denetim ekranı `BackofficeAuditFeed`'den, ofis feed ekranı `OfficeAuditFeed`'den beslenir — ikisi de sonuçta bir Filament resource / Inertia sayfasına audit verisi taşır. Kuralın niyeti ("teklifin zaman çizelgesi audit'ten gelmesin") doğru, ama tarif niyet gerektiriyor; audit **görüntüleme** ekranlarını dışlayan bir allowlist (ör. "yalnız `App\Queries\Audit\**` üzerinden ve yalnız denetim rotalarında") yazılmadan tarama ya meşru ekranları kırar ya hiçbir şeyi yakalamaz. S-14'ün "listeleme rotası yok" yarısı da küçük ölçekte aynı ihtiyacı taşıyor (`UsageLogger` INSERT'i ve `analytics_usage_daily` migration'ı `audit_usage`'a meşru dokunur); `audit_activity` grep yarısı ise tamamen mekanik ✓.

**R2-6 (minör) — B-1'in dayandığı S-4 taraması, bugünkü tarifi ile bayrağı görmez.** B-1 "oturum düzeyinde set edilmesi chunk9 S-4 taramasına takılır" diyor (`omurga-plan_chunk3.md:198`); ama S-4'ün uygulama tarifi chunk2'de **yalnız** `SET app.tenant_ids` desenini arıyor (`omurga-plan_chunk2.md:237`: *"Arch testi `SET app.tenant_ids` ifadesini arar"*). `SET app.audit_read_all` bu desene uymaz. Taramanın/arch testinin `SET app.*` genelliğine çekildiği hiçbir belgede yazılı değil — B-1'in güvencesi şu an havada.

**R2-7 (minör) — Index'in iki iç tutarsızlığı.** (a) Üst pin **v1.9** derken 2.4 revizyon girdisi *"upstream pin **v1.8**'e alındı"* diyor (`omurga-plan.md:5` ↔ `:115`) — iki commit'in izi, tek belgede iki farklı beyan. (b) Pin satırı v1.9 için *"`review-egt50-ofis-backoffice-2026-07-26.md` turundan geçti"* diyor — o tur v1.8'i **REJECTED** etti; v1.9 o turun *cevabıdır* ve onayı bu r2 turundadır. "Turundan geçti" ifadesi, henüz verilmemiş bir onayı verilmiş gösteriyor.

**R2-8 (minör) — `docs/claude/heyet.md` L-1a'yı bilmiyor.** `heyet.md:21` hâlâ kayıtsız şartsız *"Müşteri kimliklerinin denetim izi ofiste hiçbir ekranda yer almaz"* diyor. L-1a'dan habersiz bir sonraki reviewer, ofiste görünen "son aktif" damgasını bulgu diye açar — bu dosya tam da bu tür yanlış bulguları önlemek için var ve süpürmenin dışında kalmış.

**R2-9 (minör) — chunk3 §3.6'da yanlış çapraz atıf.** Metin *"kriter 16'nın imza testi bu sınırı da kapsar (dönüş tipinde agregat alan yok)"* diyor; kriter 16 yalnız **parametre** reflection'ını tanımlıyor, dönüş sınırını sınayan **15b**. Küçük ama "plan kanundur" rejiminde implementer'ı yanlış kritere yönlendirir.

**R2-10 (minör) — chunk8 kriter 9b'nin "arch taraması"nın evi yok.** 9b "(test + **arch taraması**)" diyor; bu tarama ne chunk1'in arch testlerinde ne chunk9 §9.5'in kesin listesinde tanımlı. F-7'nin dersi tam buydu: listede olmayan taramanın zorlaması yoktur. (Plan "arch testi" ve "kural taraması" terimlerini ayrı mekanizmalar için kullanıyor; "arch taraması" ikisine de bağlanmamış.)

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

1. **Bayrak neden `audit_usage`'ı da kapsıyor?** B-3 "üç audit tablosu" diyor; oysa L-3/AD-21 kullanım logunun **kimseye** satır satır gösterilmeyeceğini, backoffice'in yalnız agregat göreceğini söylüyor. Çapraz-tenant *ham* usage okumasının kullanım senaryosu nedir? Yoksa B-3 iki tabloya (`audit_writes`, `audit_access`) daralabilir ve S-11'in yüzeyi küçülür.
2. **Fırlatan varyant için `CASE` alternatifi değerlendirildi mi?** (Sets'in 2. sorusuna dürüst cevap:) Deney 11'in genellemesi doğru — PostgreSQL tek ifadede de OR operand sırasını garanti etmez, fırlatmayan varyant zorunluluğu sağlam. `CASE WHEN` değerlendirme sırasını garanti eder ve fırlatan `tenant_ids()`'i koruyabilirdi; ama hata satır-bağımlı olurdu (bağlamsız oturum NULL satır taradıkça döner, ilk NULL-olmayan satırda patlar) — deterministik "temiz hata" vermez. Yani bekçi+bedel çözümü savunulabilir; yine de bu değerlendirmenin plana bir cümleyle girmesi, ileride birinin "CASE ile fırlatan varyanta dönelim" denemesini önler.
3. **Feed'in erişim-logu yazımı hangi bağlamda?** §3.6.1 "okumanın kendisi erişim logu üretir" diyor; bu satır NULL-tenant (ofis alanı olayı) olarak mı yazılır? R2-3'ün cevabıyla birlikte netleşmeli — bayrak açıkken `AccessLogger`'ın INSERT'i hangi `tenant_id` ve hangi bağlam kuralına tabi?

## ⚠️ Upstream Findings

Yok. R2-1 spec katmanında bir tutarsızlıktır ama kilitli/onaylı bir bölüme geri dönüş değil — Y-4 bu revizyonun dokunması gerekip dokunmadığı bir satırdır (F-9 kapanışının eksik kalan yarısı).

## Previous Findings Status

| # | Durum |
|---|---|
| F-1 | ✅ Kapandı |
| F-2 | ✅ Kapandı (Sets kararı — L-1a; yazım tutarlı) |
| F-3 | ✅ Kapandı (Sets kararı — L-1b; dört katmanlı koruma yerinde, karar izi kayıtlı) |
| F-4 | ⚠ Kısmen: RLS katmanı çözüldü (bağlam beyanı); uygulama katmanı entegrasyonu (R2-3) ve bayrak yaşam döngüsü (R2-2) açık |
| F-5 | ✅ Kapandı |
| F-6 | ⚠ Kısmen: gerekçe düzeltildi; telafi taraması S-12'nin tarifi uygulanabilir değil (R2-4) |
| F-7 | ⚠ Kısmen: liste tamamlandı; S-12/S-13 tarifleri taranabilirlik şartını sağlamıyor (R2-4, R2-5) |
| F-8 | ✅ Kapandı (iki kozmetik pürüz: R2-7) |
| F-9 | ⚠ Kısmen: AD-23 düzeldi; spec Y-4'e istisna işlenmedi (R2-1) |
| F-10 | ✅ Kapandı |

## Verdict: ❌ REJECTED

On bulgunun altısı temiz kapandı; F-2/F-3 kararlarının yazımı tutarlı ve karar izi örnek nitelikte. Kalanlar dar ama implementasyon öncesi kapanmak zorunda: **R2-1** (Y-4, F-9'un taşınan çelişkisi), **R2-2** (bayrağın transaction-içi mirası — yeni desenin tek gerçek güvenlik boşluğu), **R2-3** (feed'in TenantContext zemini olmadan 17b/17e kurulamaz) ve **R2-4/R2-5** (iki taramanın tarifi mekanik değil — zorlaması olmayan kural, F-7'nin gösterdiği gibi, yok hükmündedir). Beşi de nokta düzeltmesidir; yeni bir karar gerektirmez, üçüncü turun küçük olması beklenir.
