preflight

10. Catatan keputusan

Kenapa bentuknya begini, berikut angka yang mendasarinya. Semua diukur pada aplikasi ini, bukan dikutip dari dokumentasi.

Yang salah dari dokumentasi provider

Dua angka ini menentukan hampir seluruh arsitekturnya, dan dua-duanya tidak bisa didapat dari membaca dokumen.

Model Flash penuh cuma ~20 request/hari

Quota exceeded for metric: generate_content_free_tier_requests,
limit: 20, model: gemini-3.8-flash

Banyak sumber menyebut 250. Yang benar 20 — sementara Flash-Lite dapat ~500.

Konsekuensinya langsung: kalau kuota bersama memakai model Flash, seluruh produk mentok di 10 rencana per hari. Jadi kuota bersama jalan single-tier (semua tahap di Flash-Lite), dan pengguna dengan key sendiri dapat Flash untuk PRD.

Perbandingannya diukur:

Rencana/hari per keyDurasiKualitas PRD
Dual-tier (Flash untuk PRD)1060 detik4 non-goal, lebih tajam
Single-tier (semua Flash-Lite)7139 detik3 non-goal, 1 agak meleset

Turun kualitasnya tipis; throughputnya naik 7× dan lebih cepat.

Groq membatasi output 1.000 token/menit

Dari header responsnya sendiri:

x-ratelimit-limit-requests    1000      ← yang diiklankan
x-ratelimit-limit-tokens      8000      ← per menit
OTPM (output tokens/minute)   1000      ← yang sebenarnya mengikat

Satu rencana butuh ~17.000 output token. Di 1.000 OTPM itu 17 menit per rencana. Angka "1.000 request/hari" tidak pernah relevan untuk beban kerja ini.

Groq tetap didukung, tapi bukan default. Seluruh lini model Llama juga sudah dihapus dari sana — tersisa tiga model, dan yang 20B tidak sanggup memegang skema task.

Pelajaran: ukur, jangan percaya. scripts/probe-limits.ts ada untuk itu.


Biaya satu rencana

Request AI~7
Token~20.000
Waktu40–60 detik

Perkiraan awal sebelum diukur adalah 12–20 request dan 150.000–300.000 token. Meleset sekitar 15×.

Itu bukan koreksi sepele: perkiraan yang salah membuat kesimpulan "kuota bersama tidak mungkin, BYOK wajib". Angka sebenarnya membalik kesimpulan itu — satu key gratis menampung ~71 rencana/hari, cukup untuk free tier yang mengalahkan paket berbayar kompetitor.


Yang mahal itu request, bukan token

Saat kedalaman rencana dinaikkan tiga kali lipat, biaya request tidak bergerak:

RequestTokenHasil
Sebelum713.97212 task
Sesudah719.58136 task

Karena itu batching jadi keputusan yang paling menentukan: 17 panggilan naif ditekan jadi ~7.


Model kecil punya varians tinggi, dan prompt tidak mengikatnya

Prompt yang sama, dua run berurutan:

Run ARun B
Task per subfitur2,01,3
Judul berbahasa Inggris09 dari 24

Menambal prompt dicoba berkali-kali dan tidak menempel. Yang bekerja adalah menegakkan kontraknya di kode (lib/ai/validate.ts) lalu menjalankan satu re-ask tertarget yang memperlihatkan model keluarannya sendiri beserta daftar persis apa yang salah.

Satu bug yang membuat repair loop-nya sia-sia

after.length < defects.length      // salah
severity(after) < severity(defects) // benar

Versi pertama membandingkan jumlah jenis cacat. Perbaikan yang membereskan 7 dari 10 prompt stub tetap melaporkan satu jenis cacat, jadi dianggap tidak membaik — dan hasilnya dibuang.

Gejalanya: repair loop terlihat berjalan di log, tapi stub tetap sampai ke pengguna.


Mengukur tidak sama dengan menegakkan

Panjang agent prompt diperiksa di spike.ts sejak hari pertama. Tapi pemeriksaan itu hanya mencetak peringatan — tidak ada di jalur produksi.

Akibatnya tiga prompt stub 60 karakter sampai ke rencana pengguna, padahal ambangnya sudah diketahui sejak awal.

Sekarang ambang yang sama (MIN_PROMPT_CHARS = 180) ada di validate.ts dan memicu repair loop.

Pelajaran: kalau sebuah ambang cukup penting untuk diukur, dia cukup penting untuk ditegakkan.


Jangan memotong jalan yang sudah terbukti

Saat revisi menambah fitur baru, fitur itu perlu diisi subfitur dan task.

Percobaan pertama: satu panggilan yang menghasilkan subfitur dan task sekaligus, demi hemat kuota. Hasilnya prompt 56–88 karakter, padahal pipeline utama rata-rata 352.

Sebabnya: jalur task yang sudah matang — aturan granularitas, injeksi jumlah target, repair loop — ditulis ulang dalam versi yang lebih jelek.

Percobaan kedua memakai ulang tasks() tapi melewati tahap specs(). Masih 2 stub, karena tanpa kriteria penerimaan dan edge case, model tidak punya bahan konkret.

Yang akhirnya bersih: urutan penuhexpandFeature()specs()tasks(). Tiga panggilan, hanya saat ada fitur yang ditambah.


Tier gratis memang tidak stabil

503 "high demand" muncul di empat dari tujuh run yang diukur. Di satu run, dua dari tiga model tier deep penuh bersamaan.

Mengulang ke model yang sama tidak pernah menolong. Rantai fallback antar-model yang menolong — dan pipeline selamat di semua kejadian.

Rantai awalnya salah desain: ketiga kandidat tier deep sama-sama model 20-RPD, jadi saat kuota habis dia jatuh ke sesama model yang juga habis. Sekarang rantainya berakhir di Flash-Lite yang berkuota besar.


Beban MCP

Waktu serverPanggilan AI
1× generate rencana120.478 ms17
preflight_next_task()0,049 ms0

Query-nya index scan, 3 buffer hit. Round-trip penuh lewat HTTP: 31 ms median, 66 ms p95.

Beban yang sebenarnya perlu dijaga bukan CPU, tapi konteks agent: definisi tool menetap sepanjang percakapan. Tiga tool = 1.594 byte (~400 token), dan ada asersi yang gagal kalau membengkak.

maxSubscriptions: 0 mematikan SSE, jadi agent yang nganggur tidak menahan koneksi.


Keputusan produk

Tanpa akun. Sesi anonim lewat cookie. Kompetitor mewajibkan signup untuk 1 PRD; di sini tidak ada dinding di depan hal yang orang datang untuk coba. Konsekuensinya jujur: ganti browser, rencananya hilang.

Halaman publik server-rendered. Satu rencana menghasilkan ~3.900 kata di HTML. Aplikasi kompetitor berbentuk SPA Vite — halaman /plan mereka cuma 8,5 KB shell dan /live malah merender 404 di server. Ini celah struktural yang tidak bisa ditutup tanpa menulis ulang frontend.

Menerbitkan itu opt-in dan bisa ditarik. Slug dihapus, bukan ditandai, supaya tautan lama benar-benar 404.

Batas kuota ditampilkan di depan. Batas yang tidak terlihat terasa sewenang-wenang saat menabrak.


Cara mengukur ulang sendiri

npm run spike -- --no-interview      # biaya pipeline, masukan deterministik
npm run spike -- --single-tier       # konfigurasi kuota bersama
npx tsx scripts/probe-limits.ts      # rate limit asli dari header
npx tsx scripts/list-models.ts       # model yang benar-benar hidup

Angka di dokumen ini akan usang. Skripnya tidak.