# 34 — Yazılımcı G3 · `odeme/paket-vaadi` (paketliden liste/revizyon kredisi düşmez) > Rol: `yazilimci` · Gece vardiyası, 22 Eylül 2026 sabah turu · Şartname: `28-cto-sartname.md` §G3 + `31-guvenlik-satici-kimligi.md` §2 > Dal: **`odeme/paket-vaadi`** · Taban: **`9bd448b`** (`main`) · Çalışma yeri: ana çalışma ağacı (`/Users/bilalgursen/Desktop/kolaytercih`) > İşaret: **[D]** komut çalıştırılarak doğrulandı · **[Ç]** koddan çıkarım (koşturulmadı) --- ## Özet (5 madde) 1. **Tek `maliyet = user.hasPaket ? 0 : RAPOR_KREDI` değişkeni CTO'nun saydığı altı satırı birden kapattı** — iki harcama (`amount`), iki iade (`delta`), iki dönen bakiye (`kredi:`). `spendCredits`/`grantCredits` çağrılarının hiçbiri kaldırılmadı. [D] 2. **İade dalı koşullandı** — güvenlik ajanının "sızıntı garanti" dediği yol (`listeRevize` `hasPaket` kapısının arkasında + `revisionCount` yalnız başarıda artıyor + taze `requestId`) kapandı: paketlinin başarısız denemesi artık `delta: 0` yazıyor, bedava kredi üretmiyor. 3. **Arayüz sunucuyla aynı şeyi söylüyor** — `raporKredi` paketliye 0 iner, modal tek `ucretsiz` bayrağıyla üç kredi cümlesini değiştirir; `krediYeter`/`KrediYetersiz` mantığına dokunulmadı. 4. **Doğrulama üçlüsü temiz:** `next typegen` ✓, `tsc --noEmit` çıkış 0 ve **hiç çıktı yok**, `pnpm lint` çıkış 0 ve **hiç bulgu yok**. Şartnamedeki 6 kabul grep'i tek tek koşuldu, hepsi beklenen değeri verdi. [D] 5. **Kapsam tam olarak 3 dosya.** `git diff --name-only HEAD~2 HEAD` yalnız G3'ün üç dosyasını listeliyor; `credits.ts`, `liste-uretici.tsx`, `huni-semasi.tsx` ve çalışma ağacındaki başkalarına ait commit'lenmemiş dosyalar (`AGENTS.md`, `docs/ekip/KARARLAR.md`, `content/rehber/**`) **el değmemiş** — hâlâ `M`/`??` durumunda duruyorlar. [D] --- ## Dal ve commit'ler `git checkout -b odeme/paket-vaadi main` ile `9bd448b` tabanından açıldı (önceki dal `funnel/sonuc-ilk-ekran` — G1'in dalı; ona dokunulmadı, commit alınmadı). | SHA | Mesaj | Dosya | |---|---|---| | `4acfd27` | `fix(kredi): paketliden liste ve revizyon kredisi düşmez` | `src/features/rapor/rapor-actions.ts` | | `43b6cec` | `fix(listem): fark modalı paketliye kredi bedeli göstermez` | `src/features/rapor/components/listem-icerik.tsx`, `src/features/rapor/components/tercih-degisti-modali.tsx` | `[Bilal]` commit'i yok (şartname öyle diyor: paket içeriği kararı CEO'da verilmişti). Push yok, merge yok, `main`'e commit yok. Yıkıcı git komutu (`reset`/`checkout --`/`restore`/`clean`/`stash`) **hiç çalıştırılmadı**; dosyalar yola tek tek verilerek eklendi (`git add -A` kullanılmadı). ### Dokunulan satırlar **`rapor-actions.ts`** (satır numaraları değişiklik sonrası): - `:158` yeni `const maliyet = user.hasPaket ? 0 : RAPOR_KREDI;` (+ 6 satırlık gerekçe yorumu) — `listeOlusturKilitli` - `:163` `amount: maliyet` · `:225` `delta: maliyet` (iade) · `:254` `kredi: user.creditBalance - maliyet` - `:300` ikinci `const maliyet = …` (+ yorum: kapı yüzünden burada daima 0, kapı gevşerse davranış bozulmasın) — `listeRevize` - `:304` `amount: maliyet` · `:360` `delta: maliyet` · `:382` `kredi: user.creditBalance - maliyet` - **Değişmeyen:** `:173` ve `:314` hata metinlerindeki `${RAPOR_KREDI} kredi gerekli` (bu dallara yalnız `maliyet > 0` iken erişilir), `krediBittiIsaretle`, `uretimKilidiAl/Birak`, `reports` yazımı, maskeleme dalları, `refId` zinciri. **`listem-icerik.tsx:167`** — `raporKredi={RAPOR_KREDI}` → `raporKredi={/* yorum */ user.hasPaket ? 0 : RAPOR_KREDI}`. (`=== true` **yazılmadı**; SQLite 0/1 temsili ile de doğru çalışır — şartname Risk #1.) **`tercih-degisti-modali.tsx`** — `:135` `const ucretsiz = raporKredi === 0;`; `:193` açıklama ("…güncelleme paketine dâhil, kredi düşmez."); `:263` "Güncelleme N kredi; bakiyen …" satırına `!ucretsiz` koşulu; `:290` buton metni ücretsizken "Listemi güncelle" (ok ikonu deseni aynen: metin sonunda ``). Ayrıca dosyanın tepesindeki "3 kredi" diyen eskimiş davranış yorumu güncellendi — o yorum dosyanın davranış belgesi. --- ## Doğrulama komutları ve çıktıları ``` $ pnpm exec next typegen Generating route types... ✓ Types generated successfully $ pnpm exec tsc --noEmit (çıktı yok) TSC_EXIT=0 $ pnpm lint > kolaytercih@0.1.0 lint > eslint (bulgu yok) LINT_EXIT=0 ``` `pnpm install` ve `pnpm build` **koşulmadı** (disk kısıtı, orkestratör talimatı). Dev sunucusu açılmadı, tarayıcıda doğrulama yapılmadı. --- ## Kabul kriterleri (şartname §G3) | # | Kriter | Sonuç | Nasıl doğrulandı | |---|---|:--:|---| | 1 | `grep -c "spendCredits(" rapor-actions.ts` = 2 | ✔ | **2** [D] | | 1 | `grep -c "grantCredits(" rapor-actions.ts` = 2 | ✔ | **2** [D] | | 2 | `grep -c "hasPaket ? 0 : RAPOR_KREDI"` = 2 | ✔ | **2** [D] | | 2 | `amount: maliyet\|delta: maliyet` → 4 satır | ✔ | `163, 225, 304, 360` [D] | | 2 | `delta: RAPOR_KREDI\|amount: RAPOR_KREDI` = 0 | ✔ | **0** [D] | | 2 | `creditBalance - RAPOR_KREDI` = 0 | ✔ | **0** [D] | | 3 | `refId: requestId\|refId: input.requestId` → 4 satır | ✔ | `165, 227, 306, 362` — zincir değişmedi [D] | | 4 | `listem-icerik.tsx` `raporKredi={…}` koşullu | ✔ | `:167` `user.hasPaket ? 0 : RAPOR_KREDI` [D] | | 4 | `grep -c "ucretsiz"` ≥ 3 | ✔ | **4** (`135, 193, 263, 290`) [D] | | 5 | `grep -rn "danışman sorusu" src/` — hardcoded 60 yok | ✔ | Arayüzdeki üç sonuç (`app/page.tsx:201`, `listem-govde.tsx:345`, `paket-satinal.tsx:40`) **hâlâ `URUNLER.paket.credits` / `paketKredi` interpolasyonu**; sayı hiçbirinde sabit değil. Toplam eşleşme 5'e çıktı çünkü iki yeni eşleşme benim yazdığım **kod yorumu** (`rapor-actions.ts:153`, `tercih-degisti-modali.tsx:14`) — metin değil [D] | | 6 | Kapsam dışı dosyalar el değmemiş | ✔ | `git diff --name-only HEAD~2 HEAD` = tam olarak 3 dosya; `credits.ts` / `liste-uretici.tsx` / `huni-semasi.tsx` **yok** [D] | | — | `typegen && tsc --noEmit && lint` | ✔ | Yukarıdaki çıktılar [D] | **Not — kriter 6'nın yazımı:** şartnamedeki `git diff --name-only HEAD~2` (HEAD yazılmadan) çalışma ağacını da kapsadığı için başkalarının commit'lenmemiş dosyalarını (`AGENTS.md`, `KARARLAR.md`, veli yazısı) listeliyor. Commit kapsamını gösteren doğru biçim `git diff --name-only HEAD~2 HEAD`; ikisi de koşuldu, ikinci biçim 3 dosya veriyor. --- ## Güvenlik ajanının üç koşulu — kodda nerede karşılandı | Koşul (`31-guvenlik-satici-kimligi.md` §2) | Karşılandığı yer | |---|---| | **1.** İade dalı aynı koşula bağlansın; `grantCredits` çağrısı ve `refund` satırı **kaldırılmasın** | `rapor-actions.ts:223-228` (`listeOlustur` iadesi, `delta: maliyet`) ve `:358-363` (`listeRevize` iadesi, `delta: maliyet`). İki çağrı da yerinde, `refId` aynı; DUPLICATE dalındaki "önceki deneme iade edilmişti" sorgusu (`:179-192` ve `:320-333`) değişmedi | | **2.** Dönen bakiye de koşullansın (`:243`, `:363`) | `rapor-actions.ts:254` ve `:382` → `kredi: user.creditBalance - maliyet` | | **3.** `hasPaket` **tek yerden**, zaten okunmuş `user` nesnesinden okunsun; ikinci DB okuması eklenmesin | `rapor-actions.ts:158` (`listeOlusturKilitli`'ye parametre olarak gelen `user`) ve `:300` (`listeRevize`'de `getCurrentUser()` ile bir kez okunan `user`). Yeni sorgu/okuma eklenmedi; harcama ile iade aynı fonksiyon kapsamındaki **aynı** `maliyet` sabitini kullanıyor | Ek olarak şartnamenin "çağrı kaldırılmaz" kısıtı korundu: `credit_ledger`'daki `uniqueIndex("ledger_reason_ref").on(reason, refId)` (`src/lib/appdb/schema.ts:133`) çapası aynen yerinde, paketliye `delta = 0` satır yazılıyor ve aynı `requestId` ikinci kez `DUPLICATE` dönüyor [Ç — DB ile koşturulmadı, QA'nın duman testine kaldı]. --- ## Şartnameden sapmalar 1. **`tercih-degisti-modali.tsx`'in dosya başı yorumu da güncellendi** (şartname 129/188/250/275 satırlarını sayıyordu). Gerekçe: o yorum "yeniden kurulum … 3 kredi" diyerek artık yanlış olan bir davranışı belgeliyordu; AGENTS.md'nin "belge dekor değildir" prensibiyle aynı commit'te düzeltildi. Davranışa etkisi yok. 2. **`:250` satırına `!ucretsiz` koşulu eklendi.** Şartname "ücretsizse bu satır gösterilmez" diyordu; `raporKredi = 0` iken `krediYeter` zaten daima doğru olduğu için satır teknik olarak **zaten** render edilmiyordu [Ç]. Koşul niyeti açık etmek ve `krediYeter` hesabı ileride değişirse cümlenin sızmaması için yine de yazıldı. 3. **`:129 krediYeter` değiştirilmedi** (şartname de dokunulmamasını istiyordu) — yalnız altına türetilmiş `ucretsiz` bayrağı eklendi. 4. Başka sapma yok; `huni-semasi.tsx`'e dokunulmadı (CTO doğrulaması: G3 sihirbaz/liste mimarisini değiştirmiyor), paket adına (A2) dokunulmadı, `credits.ts`/`liste-uretici.tsx` açılmadı bile. --- ## Merge sonrası doğrulanması gerekenler (QA / `guvenlik-uyum`) 1. **Oturumlu duman testi (paketli kullanıcı):** liste üretimi sonrası `user.credit_balance` **değişmiyor**, `credit_ledger`'a `reason='report_generate', delta=0` satırı yazılıyor; ekranda görünen bakiye de düşmüyor. Aynısı revizyonda (`reason='report_revision'`). 2. **Başarısız üretim (paketli):** yapay zekâ hatası tetiklenince `reason='refund', delta=0` satırı yazılıyor ve bakiye **artmıyor** — güvenlik ajanının B2 sızıntısının kapandığının tek gerçek kanıtı budur. 3. **Idempotency:** aynı `requestId` ile ikinci üretim `DUPLICATE` yoluna giriyor; iade satırı varsa "tekrar dener misin", yoksa `SURUYOR`. `spendCredits`'in `amount: 0` ile `rowsAffected = 1` döndürmesi (yani `INSUFFICIENT` **dönmemesi**) SQLite'ta fiilen teyit edilmeli — şartnamede de [Ç] işaretliydi, ben de koşturmadım. 4. **Paketsiz kullanıcıda davranış bit-bit aynı:** 3 kredi düşer, yetersizse `KREDI` + `krediBittiIsaretle`, modal eski metinleri gösterir. 5. **Bilinen ve kapsam dışı bırakılan tutarsızlıklar:** `liste-uretici.tsx:263-285`'teki `hasPaket` "kredi yetersiz/+30 kredi yükle" dalı liste üretimi için artık ölü kod (Bilal'in dosyası → dokunulmadı, backlog #B2); `kredi-hatirlatma.ts:36` + `eposta.ts:188` paketliye yanlış metin gönderebilir (G3 öncesinden var, backlog #B3). 6. Para yüzeyine dokunuldu → **`guvenlik-uyum` denetimi merge öncesi zorunlu** (şartname de öyle diyor; bu dal için §2'deki üç koşul karşılandı, denetimin işi doğrulamak). --- ## Bilal'den istenen 1. **Yok** — G3 tamamlandı, `[Bilal]` kararı gerektiren bir satır çıkmadı. Merge kararı sabahki entegrasyon turunda.