# Review — Potansiyel müşteri — implementasyon planı (v1.3) — 2026-10-20 (re-review 3)

> **Review type:** plan-re-review
> **Previous reviews:** heyet 809 (REJECTED, F-1…F-6), heyet 810 (REJECTED, F-7), heyet 811 (APPROVED, v1.2) — uygulamaya başlarken v1.2'nin K-25'inin gerçeğe uymadığı anlaşıldı, plan v1.3'e revize edildi.
> **Upstream document(s) read:** `proje-haritasi.md` §4.4 (dokuz madde + 19.10.2026'nın iki kararı + 20.10.2026'nın yeni kararı: "örtük `TenantContext::forOffice` bloğu değil açık parametre"), `docs/arch/mimari-kararlar.md` (AD-04, AD-06, AD-21, AD-23, AD-25, AD-26), `CLAUDE.md`.
> **Other cross-referenced documents:** Bu turun kapsamı (K-25'in yeniden yazımı, Görev 5 adım 6-8, Görev 5b, revizyon satırı) tek tek koddan açıldı: `app/Support/Audit/AuditWriter.php` (tam dosya — `record()`'un `$tenantId ?? CurrentActor::tenantId()` satırı, iddia edilen satır 63 ile eşleşiyor), `app/Support/Audit/AuditDriver.php` (tam dosya — `tenantOf(Auditable $model)` private metodu, iddia edilen satır aralığı 79-92 ile örtüşüyor), `app/Support/Audit/Concerns/PersistsAuditRows.php` (tam dosya — bugün paylaşılan bir `tenantOf` **yok**; üç yazıcının üçü de aynı deseni ayrı ayrı tekrarlıyor, plan'ın "üç yazıcının üçü de" iddiası doğru), `app/Models/RecordNote.php`, `app/Models/Task.php`, `app/Models/SalesMeeting.php` (üçü de `implements Auditable` + `AuditableTrait`, hiçbiri `BelongsToTenant` kullanmıyor — plan'ın "ortak modeller" iddiasının temeli), `app/Actions/Office/AddCustomerNote.php` (mevcut müşteri-konulu not yazımının zaten `TenantContext::forWrite($customer)` içinde olduğu — K-25'in "false dalı mevcut sarmalamaya güvenir" varsayımının kanıtı). Önceki turların doğrulanmış kod kanıtları (`TenantContext.php`, `SessionScopeResolver.php`, `CreateCustomerPerson.php`, `Masker.php`, `config/tenancy.php`, `CloseMeeting.php`, `CustomerPeople.php`) bu turda tekrar açılmadı.
> **Stage locks in effect:** Sets'in dokuz + iki + bir (20.10.2026) kararı kilitli. Brief'in sınırladığı gibi yalnız K-25'in yeni tasarımı, Görev 5'in 6-8. adımları, Görev 5b ve revizyon satırı değerlendirildi; diğer bölümler 811'de APPROVED ve bu turda yeniden açılmadı.

---

## Upstream Coverage Matrix

(Yalnız bu turun kapsamındaki madde için, sıfırdan üretildi.)

| Upstream § / madde | Reviewed doc'ta durumu | Kanıt |
|---|---|---|
| Sets kararı (20.10.2026): örtük blok değil, açık parametre + doğrulanan beyan | ✓ | K-25 artık `officeRecord: true` (AuditWriter, AccessLogger) + `OfficeRecord::belongsToNoCustomer()` (model audit'i) + `assertOfficeRecord` (beyanı doğrular, kiracılı konuda `LogicException`). `TenantContext::forOffice` kullanılmıyor — Sets'in "örtük blok her yazmayı kiracısız yapar, kiracılı yazılması gereken satırı da" itirazı mimari olarak karşılanmış |
| Uygulamada bulunan genişleme: aynı kusur `AuditWriter`/`AuditDriver`'da da var | ✓ | Bağımsız kod okuması doğruladı: `AuditWriter.php`'de `record()` doğrudan `$tenantId ?? CurrentActor::tenantId()` yapıyor (ayrı bir `tenantOf` yok), `AuditDriver.php`'de kendi `tenantOf()`'u aynı deseni tekrarlıyor — üç yazıcı, üç ayrı kopya, hiçbiri paylaşılan bir metottan geçmiyor. Plan'ın iddiası doğru |
| `RecordNote`/`Task`/`SalesMeeting` potansiyel kayda yazıldığında yanlış kiracıya düşme riski | ✓ | Üçü de `implements Auditable` (`AuditableTrait` kullanıyor), hiçbiri `tenant_id` kolonu taşımıyor (`BelongsToTenant` yok) — potansiyel-konulu bir not/görev/görüşme tenant bağlamı açılmadan yazıldığında (K-3'ün kuralı) `AuditDriver::tenantOf` eskiden ambient scope'a düşerdi; K-25'in `OfficeRecord` sözleşmesi bunu `belongsToNoCustomer()===true` durumunda doğrulanmış NULL'a çeviriyor |
| Mevcut müşteri-konulu not/görev/görüşme regresyonu (false dalı) | ✓ | `belongsToNoCustomer()===false` durumunda mekanizma hâlâ çağıranın `TenantContext::forWrite(customer)` sarmalamasına dayanıyor — bu, `AddCustomerNote.php`'de bugün zaten var olan, bağımsız doğrulanmış bir davranış; K-25 bunu değiştirmiyor, yalnız `true` dalını güvenli hâle getiriyor |
| Görev 5 adım 6: yeniden bağlama artık `TenantContext::forWrite(customer)` içinde, model üzerinden (toplu UPDATE değil) | ✓ | v1.2'de bu adım ham `UPDATE … WHERE subject_type/id = prospect` idi — Eloquent/`AuditableTrait` bunu hiç görmez, reassignment audit'siz kalırdı. v1.3 bunu model-bazlı yazmaya çevirmiş: hem doğru kiracıya hem audit'li — bu, önceki turlarda fark edilmemiş ek bir düzeltme |
| Görev 5 adım 7-8: prospect'in kendi durumu hâlâ kiracısız, dönüşüm olayı `officeRecord: true` ile | ✓ | `prospect`'in durumu `converted`'e çekilirken model hâlâ `OfficeRecord` (`belongsToNoCustomer()` hep `true`); `potential_customer.converted` olayı `AuditWriter::record(…, officeRecord: true)` ile elle işaretlenmiş |
| `assertOfficeRecord`'un dürüstlüğü: beyan yanlışsa sessiz NULL değil, `LogicException` | ✓ | Konunun tablosu `exempt_tables`'ta değilse ya da konuda `tenant_id` özniteliği varsa patlıyor — bu, tam olarak kırmızı çizgi 1/AD-21'in istediği "yanlış beyan sessizce geçmesin" garantisi |
| Dört mevcut ofis okumasının aynı kusuru taşıması — kapsam dışı | ✓ | "Kapanış adresi verilen" tablosuna satır eklenmiş: "Dört mevcut ofis okumasının kiracısız erişim logu (K-25'in diğer çağıranları) → EGT-220". Ticket disiplinine uygun — bu plan onları sessizce düzeltmiyor |
| Görev 5b testleri K-25'in her üç yazıcısını ve her iki dalını (true/false) kapsıyor mu | ✓ | `OfficeRecordAuditTest`: üç yazıcının beyanlı NULL yazdığı + INSERT politikasının kabul ettiği + kiracılı konuya `officeRecord: true` verilince `LogicException` + satır yazılmadığı + müşteriye ait not/görev/görüşmenin `belongsToNoCustomer()===false` döndüğü ve audit'inin müşteri kiracısını taşıdığı + dönüşüm sonrası yeniden bağlanan kayıtların audit'lerinin **yeni müşterinin** kiracısını taşıdığı — altı senaryo da yazılı |
| Regresyon: `MyQuotes`'ın `quote.read`'i etkilenmiyor mu | ✓ | Dosya haritası ve Görev 5b metni ikisi de "mevcut `MyQuotes` `quote.read` testi değişmeden geçer" diyor; `officeRecord` parametresi varsayılan `false` ve bayraksız çağrıların davranışı değişmiyor (plan K-25'in son cümlesi) |

---

## ✅ What works

- **Kök nedene gidilmiş, semptoma değil.** 810'un K-25'i yalnız `AccessLogger`'ı düzeltmişti; uygulama sırasında aynı "tenant'sız subject'te ambient-scope'a düşme" deseninin `AuditWriter` ve `AuditDriver`'da da — üç ayrı kopya hâlinde — var olduğu ortaya çıktı. v1.3 bunu tek bir kavramsal çözümle (açık beyan + doğrulama) üç yazıcıya birden uyguluyor; yama üstüne yama değil.
- **Sets'in 20.10.2026 itirazı (örtük blok yerine açık parametre) mimari olarak doğru karşılanmış.** `TenantContext::forOffice()` kullanılmamış olması önemli: o blok içindeki *her* yazmayı kiracısız yapardı, oysa K-25'in asıl riski tam tersiydi — kiracılı yazılması gereken bir satırın yanlışlıkla kiracısız gitmesi değil, kiracısız olması gereken bir satırın yanlışlıkla (ambient scope'tan) kiracılı gitmesiydi. Açık parametre + `assertOfficeRecord`'un doğrulaması, "beyan yanlışsa sessiz geçmez, patlar" garantisini veriyor — Sets'in cümlesiyle birebir örtüşüyor.
- **`false` dalının mevcut davranışa dayanması bilinçli ve doğrulanmış bir tercih.** Plan yeni bir mekanizma icat etmek yerine `AddCustomerNote`'un bugün zaten yaptığı `TenantContext::forWrite(customer)` sarmalamasına güveniyor; bunu bağımsız olarak kodda doğruladım — gerçekten var ve gerçekten doğru kiracıyı üretiyor.
- **Görev 5 adım 6'daki "toplu UPDATE değil, model üzerinden" değişikliği, önceki üç turda da fark edilmemiş gizli bir eksiği düzeltiyor:** ham `UPDATE` reassignment'ı audit'siz bırakırdı (Eloquent/`AuditableTrait` devreye girmezdi); model-bazlı yazım hem doğru kiracıyı hem audit satırını garanti ediyor.
- **Kapsam disiplini korunmuş:** dört mevcut çağıranın aynı kusuru taşıması saklanmamış, EGT-220'ye yönlendirilmiş; bu plan onları sessizce "madem buradayım" diye düzeltmiyor.
- Test planı (`OfficeRecordAuditTest` + Görev 5b'nin genişletilmiş senaryoları) hem `true` hem `false` dalını, hem yanlış-beyan durumunu hem dönüşüm sonrası kiracı değişimini kapsıyor.

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

Yok. Matrix'te ❌/⚠ satır yok.

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

Yok.

## Previous Findings Status (re-review only)

| Bulgu | Durum |
|---|---|
| F-7 (heyet 810, `AccessLogger`'a özel çözüm) | Üzerine inşa edildi — kapsamı `AuditWriter`/`AuditDriver`'ı da içerecek şekilde genişletildi, kök nedene gidildi |
| v1.2'nin "gerçeğe uymayan" K-25'i | ✅ Resolved — yeni tasarım (açık parametre + doğrulanan sözleşme) kodda var olan üç ayrı tekrarın hepsini kapsıyor |

Düzeltme yeni bir problem yaratmadı; planın ana hedefinden sapma yok. Bu, ironik biçimde iyi bir sinyal: 811'in APPROVED'ı uygulamaya geçerken yanlış çıktı ve süreç bunu sessizce geçmek yerine plana geri döndü, kök nedeni buldu ve kapsamı genişletti — tam da bu heyet protokolünün "onaylı plan gerçeğe uymuyorsa DUR ve plana dön" ilkesinin işlediği an.

## Verdict: ✅ APPROVED

K-25'in yeniden yazımı, Görev 5'in 6-8. adımlarındaki bağlam ayrımı ve Görev 5b'nin genişletilmiş testleri — bu turun kapsamındaki her madde — koddan doğrulandı ve tutarlı. Sets'in 20.10.2026 kararı (açık parametre, örtük blok değil) doğru uygulanmış; mekanizma hem yeni özelliğin kendi yazmalarını hem mevcut emsal davranışı (MyQuotes, AddCustomerNote) doğru ayırt ediyor. Kapsam dışı bırakılan dört mevcut çağıran (EGT-220) doğru adreslenmiş. Matrix'te açık satır yok; plan implementasyona hazırdır.

```
docs/reviews/review-potansiyel-musteri-plan-re-review-3-2026-10-20.md
```
