[{"data":1,"prerenderedAt":326},["ShallowReactive",2],{"tag-labels":3,"site-header":4,"article-breakpoint-on-the-wrong-block-id":72},{},{"featuredPost":5,"navigations":29},{"id":6,"title":7,"title_id":8,"slug":9,"excerpt":10,"excerpt_id":11,"has_translation":12,"published_at":13,"reading_time":14,"hidden_from_listing":15,"tags":16,"thumbnail_image":21,"og_image":22,"series":23,"authors":28},110,"When You Pick a Framework Just to Look Different","Ketika Pilih Framework Cuma Biar Kelihatan Beda","ketika-pilih-framework-cuma-biar-kelihatan-beda","The last time you chose a new framework or library, was it because your problem needed that tool, or because it sounded cool and few people around you were using it? That question is uncomfortable. Technology decisions are often made for reasons that never appear in any technical document.","Terakhir kali kamu milih framework atau library baru, itu karena masalahmu butuh alat itu, atau karena alatnya kedengaran keren dan belum banyak yang pakai? Pertanyaan ini nggak enak dijawab. Soalnya keputusan teknologi sering diambil dengan alasan yang nggak pernah ditulis di dokumen teknis mana pun.",true,"2026-10-06T15:25:21.000Z",5,false,[17,18,19,20],"karier","framework","opini","pengalaman",null,"\u002Fog\u002Fketika-pilih-framework-cuma-biar-kelihatan-beda.png",{"id":24,"title":25,"title_id":26,"slug":27},9,"Articles","Artikel","all",[],[30,46,67],{"collection":31,"item":32},"series",{"__typename":31,"title":25,"title_id":26,"slug":27,"children_series":33},[34,38,42],{"title":35,"title_id":36,"slug":37},"Artificial Intelligence","Kecerdasan Artifisial","kecerdasan-artifisial",{"title":39,"title_id":40,"slug":41},"Programming Fundamentals","Konsep Dasar Pemrograman","konsep-dasar-pemrograman",{"title":43,"title_id":44,"slug":45},"Algorithms and Data Structures","Algoritma dan Struktur Data","algoritma-struktur-data",{"collection":31,"item":47},{"__typename":31,"title":48,"title_id":48,"slug":49,"children_series":50},"Tutorial","tutorial",[51,55,59,63],{"title":52,"title_id":53,"slug":54},"Learning Python","Belajar Python","belajar-python",{"title":56,"title_id":57,"slug":58},"Learning Go","Belajar Golang","belajar-golang",{"title":60,"title_id":61,"slug":62},"Learning Java","Belajar Java","belajar-java",{"title":64,"title_id":65,"slug":66},"Learning Pascal","Belajar Pascal","belajar-pascal",{"collection":31,"item":68},{"__typename":31,"title":69,"title_id":69,"slug":70,"children_series":71},"Lab","lab",[],{"article":73,"renderedBody":200,"renderedTakeaway":201,"latestArticles":202,"toc":306},{"id":74,"title":75,"title_id":75,"slug":76,"excerpt":77,"excerpt_id":77,"has_translation":12,"published_at":78,"reading_time":79,"hidden_from_listing":12,"tags":80,"thumbnail_image":21,"og_image":84,"series":85,"authors":191,"seoTitle":21,"seoDescription":21,"body_locale":194,"available_locales":195,"body":197,"takeway":198,"prerequisite":199},142,"Jawabannya: Breakpoint-nya Ada di Blok yang Salah","breakpoint-on-the-wrong-block","Delapan keadaan terukur dari loop yang sama, dari 0,0% ke 90,9% cache hit: perbaikan mana yang menggerakkan tagihan, dua perbaikan yang tidak mengubah apa pun, dan kenapa transkripnya jadi lebih panjang sementara biayanya turun.","2026-11-08T01:30:00.000Z",3,[70,81,82,83],"llm","cache","api","\u002Fog\u002Fbreakpoint-on-the-wrong-block.png",{"id":86,"title":69,"title_id":69,"slug":70,"description":87,"description_id":88,"articles":89,"children_series":190,"parent_series":21},29,"Practice labs: work the problem first, then read the answer. Every lab ships with a repo you can clone, production-sized data, and a target you have to hit yourself. The write-up lives in this series too, and it only opens from the problem article.","Lab praktik: kerjakan masalahnya dulu, baru lihat jawabannya. Tiap lab punya repo yang bisa di-clone, data seukuran produksi, dan target yang harus kamu capai sendiri. Artikel jawabannya ada di seri ini juga, dan cuma bisa kamu buka dari artikel masalahnya.",[90,111,129,144,161,176],{"id":91,"title":92,"title_id":93,"slug":94,"excerpt":95,"excerpt_id":96,"has_translation":12,"published_at":97,"reading_time":14,"hidden_from_listing":15,"tags":98,"thumbnail_image":21,"og_image":102,"series":103,"authors":104},104,"N+1 Was Never the Bottleneck: 41 Queries Down to 2, Still One Second","Query-nya Tinggal 2, Tapi Response-nya Masih 1 Detik","query-tinggal-2-tapi-response-masih-1-detik","A feed endpoint that shows 20 posts takes a full second and hits the database with 41 queries. Apply the standard N+1 advice, get it down to 2 queries, and the latency does not move. This is that problem as it happened, plus the lab.","Endpoint feed yang cuma menampilkan 20 tulisan butuh satu detik, dan server database dihujani 41 query. Kamu kerjakan nasihat N+1 yang standar, query-nya turun jadi 2, dan latency-nya nggak bergerak. Ini versi \"apa adanya\" dari masalah itu, plus lab-nya.","2026-10-04T09:59:21.000Z",[99,100,101],"database","performance","backend","\u002Fog\u002Fquery-tinggal-2-tapi-response-masih-1-detik.png",{"id":86,"title":69,"title_id":69,"slug":70},[105],{"authors_id":106},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},1,"Daffa Izzuddin","izzudd","Writer",{"id":112,"title":113,"title_id":114,"slug":115,"excerpt":116,"excerpt_id":117,"has_translation":12,"published_at":118,"reading_time":119,"hidden_from_listing":15,"tags":120,"thumbnail_image":21,"og_image":124,"series":125,"authors":126},114,"One Payment, Four Ledger Rows: An Idempotency Lab","Saldo Naik Empat Kali untuk Satu Pembayaran","saldo-naik-empat-kali-untuk-satu-pembayaran","The code is not wrong and the gateway is not wrong, yet one payment shows up four times in the ledger. Guess why, then make `make check` green in the lab.","Kodenya nggak salah, dan gateway-nya juga nggak salah. Tapi satu pembayaran muncul empat kali di ledger. Coba tebak kenapa — lalu bikin `make check` hijau di lab-nya.","2026-10-11T13:45:00.000Z",4,[121,122,123,99,70],"idempotency","webhook","postgres","\u002Fog\u002Fsaldo-naik-empat-kali-untuk-satu-pembayaran.png",{"id":86,"title":69,"title_id":69,"slug":70},[127],{"authors_id":128},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":130,"title":131,"title_id":132,"slug":133,"excerpt":134,"excerpt_id":135,"has_translation":12,"published_at":136,"reading_time":79,"hidden_from_listing":15,"tags":137,"thumbnail_image":21,"og_image":139,"series":140,"authors":141},116,"The Webhook Arrived Late. The Reconciliation Job Had Already Run.","Webhook-nya Telat, Job Rekonsiliasinya Keburu Jalan","webhook-telat-job-rekonsiliasi-keburu-jalan","The webhook path is already idempotent. Then a morning reconciliation job appears, and one payment gets recorded twice from two paths that are both right. Guess where the key is wrong.","Jalur webhook sudah idempotent. Lalu ada job rekonsiliasi pagi, dan satu pembayaran tercatat dua kali dari dua jalur yang dua-duanya benar. Coba tebak kuncinya salah di mana.","2026-10-11T13:44:00.000Z",[121,138,122,123,70],"reconciliation","\u002Fog\u002Fwebhook-telat-job-rekonsiliasi-keburu-jalan.png",{"id":86,"title":69,"title_id":69,"slug":70},[142],{"authors_id":143},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":145,"title":146,"title_id":147,"slug":148,"excerpt":149,"excerpt_id":150,"has_translation":12,"published_at":151,"reading_time":119,"hidden_from_listing":15,"tags":152,"thumbnail_image":21,"og_image":156,"series":157,"authors":158},120,"Every Receipt in This Café Lists the Same Order","Tiap Nota di Kafe Ini Isinya Pesanan yang Sama","tiap-nota-isinya-pesanan-yang-sama","Every table's receipt holds the same items, and the total is Rp0 — even though each table ordered exactly one thing. Guess why, then make `make check` green. A Python scope and mutation lab.","Nota tiap meja isinya sama semua, dan totalnya Rp0 — padahal tiap meja cuma pesan satu barang. Coba tebak kenapa.","2026-10-11T23:00:15.000Z",[153,154,155,70],"python","scope","mutasi","\u002Fog\u002Ftiap-nota-isinya-pesanan-yang-sama.png",{"id":86,"title":69,"title_id":69,"slug":70},[159],{"authors_id":160},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":162,"title":163,"title_id":164,"slug":165,"excerpt":166,"excerpt_id":167,"has_translation":12,"published_at":151,"reading_time":119,"hidden_from_listing":15,"tags":168,"thumbnail_image":21,"og_image":171,"series":172,"authors":173},122,"A Script That Cannot Say Where It Went Wrong","Script yang Nggak Bisa Bilang di Mana Salahnya","script-yang-tidak-bilang-di-mana-salahnya","A script that stops at the first bad line reports only part of the problem. This is what shows up on screen right now.","Script yang berhenti di baris jelek pertama cuma melaporkan sebagian masalah yang ada. Ini yang muncul di layar sekarang.",[153,169,170,70],"error-handling","validasi","\u002Fog\u002Fscript-yang-tidak-bilang-di-mana-salahnya.png",{"id":86,"title":69,"title_id":69,"slug":70},[174],{"authors_id":175},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":177,"title":178,"title_id":179,"slug":180,"excerpt":181,"excerpt_id":182,"has_translation":12,"published_at":183,"reading_time":79,"hidden_from_listing":15,"tags":184,"thumbnail_image":21,"og_image":185,"series":186,"authors":187},141,"A 6,000-Token Handbook and a 0% Cache Hit Rate","Buku Panduan 6.000 Token dan Hit Rate Cache 0%","cache-hit-rate-zero","Twenty-four turns, caching switched on, and a bill 21% higher than running with no cache at all. A support agent whose prompt looks static, and the three lines that quietly change it every turn.","Dua puluh empat giliran, caching menyala, dan tagihan 21% lebih tinggi daripada menjalankannya tanpa cache sama sekali. Agen support yang prompt-nya kelihatan statis, dan tiga baris yang diam-diam mengubahnya tiap giliran.","2026-11-08T01:20:00.000Z",[70,81,82,83],"\u002Fog\u002Fcache-hit-rate-zero.png",{"id":86,"title":69,"title_id":69,"slug":70},[188],{"authors_id":189},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},[],[192],{"authors_id":193},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},"id",[196,194],"en","\n**Ini artikel jawabannya.** Kalau kamu belum mengerjakan lab 6 dan masih mau mencoba sendiri, tutup dulu halaman ini. Sisanya di bawah adalah jawabannya, lengkap dengan angka pengukurannya.\n\nBagian menariknya bukan perbaikannya. Yang menarik: tiga dari lima suntingan tidak mengubah angka apa pun selama dua tahap, dan yang mengubah segalanya cuma satu baris yang tidak akan ditandai siapa pun saat review.\n\n## Delapan keadaan, satu loop\n\nDiukur dengan `scripts\u002Fcheck.py`, di mesin yang sama, tanpa mengubah `data\u002F`, `scripts\u002Fcheck.py`, atau `agent\u002Fprovider.py`:\n\n| tahap | perubahan | hit rate | tagihan | hijau |\n|---|---|---|---|---|\n| 0 | apa adanya | 0,0% | $0,4841 | 0\u002F7 |\n| 1 | jam keluar dari system prompt | 0,0% | $0,4840 | 0\u002F7 |\n| 2 | + breakpoint di ujung buku panduan | 0,0% | $0,4840 | 0\u002F7 |\n| 3 | + array tool yang stabil | 78,4% | $0,1865 | 2\u002F7 |\n| 4 | + transkrip append-only | 80,4% | $0,1857 | 4\u002F7 |\n| 5 | + tanggal pindah ke giliran user | 80,4% | $0,1860 | 5\u002F7 |\n| 6 | + TTL satu jam untuk buku panduan | 90,9% | $0,1437 | 6\u002F7 |\n| 7 | + loop melaporkan angkanya sendiri | 90,9% | $0,1437 | 7\u002F7 |\n\nPermintaan yang sama dengan caching dimatikan menagih $0,4017 di tahap 0 dan $0,4218 di tahap 7. Angka kedua lebih besar karena loop yang diperbaiki membawa transkripnya alih-alih meringkasnya.\n\n## Array tool, tempat uangnya berada\n\n```python\ndef tools_for_request() -> list[dict]:\n    return TOOLS\n```\n\nTahap 3 cuma satu baris, dan dia menaikkan hit rate dari nol ke sebagian besar. Provider mem-hash definisi tool sebelum menghash system prompt, jadi field `notes` yang berisi waktu snapshot registry membatalkan semua yang di bawahnya, di setiap permintaan, selamanya. Model tidak pernah membaca field itu. Dia ada untuk manusia.\n\nUrutannya juga penting. Menghapus timestamp dari system prompt di tahap 1 benar dan tidak membeli apa pun, karena tools-nya masih menyerahkan prefix berbeda ke cache tiap giliran. Sebuah prefix hanya sekuat bagiannya yang paling tidak stabil, dan tools duduk di paling atas.\n\n## Breakpoint, dan tanggal yang harus pindah\n\nBreakpoint mengerjakan dua hal: menulis entri di batas itu, dan menjadi posisi yang dicari mundur oleh permintaan berikutnya. Memarkirnya di pesan terakhir berarti entrinya ditulis di batas yang diperpanjang giliran berikutnya, jadi permintaan berikutnya tidak menemukan apa pun kecuali jendela pencariannya mencapai tulisan yang lebih lama.\n\n```python\nblocks = [Block(role=\"system\", text=system_prompt(), cache=True, ttl=LONG_TTL)]\n```\n\nDua breakpoint akhirnya menjadi bentuk yang benar: satu di ujung buku panduan, disimpan sejam, dan satu di ujung transkrip yang tumbuh, disimpan lima menit bawaan. Yang pertama adalah yang dibagi semua tiket; yang kedua adalah yang menyelamatkan giliran sebelumnya.\n\nTanggalnya lalu harus pindah, bukan hilang. Pemeriksaan C gagal kalau prefix statis berubah antara dua hari, dan gagal lagi kalau tanggalnya tidak pernah sampai ke model, jadi satu-satunya perbaikan yang lolos keduanya adalah mencap gilirannya:\n\n```python\nhistory.append({\"role\": \"user\", \"text\": f\"{text}\\n\\n[session date {today(provider.clock)}]\"})\n```\n\nTahap 5 adalah tempat pemeriksaan C jadi hijau sementara tagihannya tidak bergerak sama sekali, dan itulah intinya. Kebenaran dan biaya adalah dua gerbang terpisah di sini.\n\n## Penulisan ulang yang tidak dihitung siapa pun\n\nSetiap giliran ketiga loop mengganti transkrip dengan ringkasan satu baris. Itu menghemat 10.029 token selama satu jalan dan membuat setiap prefix setelah yang kedua tidak berguna. Versi yang diperbaiki mengirim 174.883 token dibanding 164.854 milik versi awal, dan membayar $0,1437 dibanding $0,4841.\n\nKalau kamu perlu ringkasan, tambahkan sebagai pesan baru di ujung. Blok sebelumnya tetap utuh, prefix-nya masih cocok, dan ringkasannya menjadi bagian dari riwayat yang di-cache alih-alih lubang di dalamnya.\n\n## Masa hidup itu pengali tagihan, bukan detail\n\nDengan bawaan lima menit, diamnya pelanggan selama sepuluh menit menagih satu penulisan ulang penuh 6.135 token per tiket. Dengan penulisan satu jam di 1,25x hanya untuk blok itu, jedanya gratis: giliran sesudahnya membaca 6.135 token dari cache. Premi tulisnya dibayar sekali per jam per buku panduan, dan buku panduannya tidak berubah.\n\nPerhatikan bentuk keputusannya. Blok statis mendapat penulisan mahal yang berumur panjang; transkrip mendapat yang murah dan berumur pendek. Satu TTL untuk seluruh prompt akan salah di dua arah sekaligus.\n\n## Penghitungnya bagian dari perbaikannya\n\nPemeriksaan G ada di urutan terakhir karena suatu alasan. Dia menjalankan loop sebagai program dan membandingkan baris yang dicetaknya dengan ledger:\n\n```plain\n$ python3 agent\u002Floop.py\nsummary turns=24 hit_rate=0.909 cost_usd=0.143682\n```\n\nTanpa baris itu, tahap 0 dan tahap 7 tidak bisa dibedakan dari luar: dua-duanya menjawab semua tiket, dua-duanya keluar dengan kode 0, dua-duanya kelihatan baik-baik saja. Angka yang dilaporkan loop tentang dirinya sendiri dan diturunkan ulang oleh pemeriksa adalah bedanya perbaikan dengan keyakinan.\n","- **Array tool adalah satu-satunya baris yang mahal.** Timestamp registry di dalam deskripsi tool menahan hit rate di 0,0%; membuat definisinya konstan menaikkannya ke 78,4%.\n- **Memindahkan jam dan breakpoint saja tidak mengubah apa pun.** Keduanya perlu, tidak satu pun cukup, dan keluaran `make check` mengatakannya di setiap tahap.\n- **Penulisan ulang transkrip membeli 10.029 token dan menagih empat kali lipat.** Loop yang diperbaiki mengirim 6% token lebih banyak dan membayar 34% dari jalan tanpa cache.\n- **Penulisan satu jam adalah yang bertahan melewati jeda sepuluh menit.** Setelah jeda, giliran berikutnya membaca 6.135 token dari cache alih-alih menulisnya ulang.",{"id":177,"title":178,"slug":180},"\u003Cp>\u003Cstrong>Ini artikel jawabannya.\u003C\u002Fstrong> Kalau kamu belum mengerjakan lab 6 dan masih mau mencoba sendiri, tutup dulu halaman ini. Sisanya di bawah adalah jawabannya, lengkap dengan angka pengukurannya.\u003C\u002Fp>\n\u003Cp>Bagian menariknya bukan perbaikannya. Yang menarik: tiga dari lima suntingan tidak mengubah angka apa pun selama dua tahap, dan yang mengubah segalanya cuma satu baris yang tidak akan ditandai siapa pun saat review.\u003C\u002Fp>\n\u003Ch2 id=\"delapan-keadaan-satu-loop\">Delapan keadaan, satu loop\u003C\u002Fh2>\n\u003Cp>Diukur dengan \u003Ccode>scripts\u002Fcheck.py\u003C\u002Fcode>, di mesin yang sama, tanpa mengubah \u003Ccode>data\u002F\u003C\u002Fcode>, \u003Ccode>scripts\u002Fcheck.py\u003C\u002Fcode>, atau \u003Ccode>agent\u002Fprovider.py\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>tahap\u003C\u002Fth>\n\u003Cth>perubahan\u003C\u002Fth>\n\u003Cth>hit rate\u003C\u002Fth>\n\u003Cth>tagihan\u003C\u002Fth>\n\u003Cth>hijau\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>0\u003C\u002Ftd>\n\u003Ctd>apa adanya\u003C\u002Ftd>\n\u003Ctd>0,0%\u003C\u002Ftd>\n\u003Ctd>$0,4841\u003C\u002Ftd>\n\u003Ctd>0\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>1\u003C\u002Ftd>\n\u003Ctd>jam keluar dari system prompt\u003C\u002Ftd>\n\u003Ctd>0,0%\u003C\u002Ftd>\n\u003Ctd>$0,4840\u003C\u002Ftd>\n\u003Ctd>0\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>2\u003C\u002Ftd>\n\u003Ctd>+ breakpoint di ujung buku panduan\u003C\u002Ftd>\n\u003Ctd>0,0%\u003C\u002Ftd>\n\u003Ctd>$0,4840\u003C\u002Ftd>\n\u003Ctd>0\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>3\u003C\u002Ftd>\n\u003Ctd>+ array tool yang stabil\u003C\u002Ftd>\n\u003Ctd>78,4%\u003C\u002Ftd>\n\u003Ctd>$0,1865\u003C\u002Ftd>\n\u003Ctd>2\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>4\u003C\u002Ftd>\n\u003Ctd>+ transkrip append-only\u003C\u002Ftd>\n\u003Ctd>80,4%\u003C\u002Ftd>\n\u003Ctd>$0,1857\u003C\u002Ftd>\n\u003Ctd>4\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>5\u003C\u002Ftd>\n\u003Ctd>+ tanggal pindah ke giliran user\u003C\u002Ftd>\n\u003Ctd>80,4%\u003C\u002Ftd>\n\u003Ctd>$0,1860\u003C\u002Ftd>\n\u003Ctd>5\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>6\u003C\u002Ftd>\n\u003Ctd>+ TTL satu jam untuk buku panduan\u003C\u002Ftd>\n\u003Ctd>90,9%\u003C\u002Ftd>\n\u003Ctd>$0,1437\u003C\u002Ftd>\n\u003Ctd>6\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>7\u003C\u002Ftd>\n\u003Ctd>+ loop melaporkan angkanya sendiri\u003C\u002Ftd>\n\u003Ctd>90,9%\u003C\u002Ftd>\n\u003Ctd>$0,1437\u003C\u002Ftd>\n\u003Ctd>7\u002F7\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Permintaan yang sama dengan caching dimatikan menagih $0,4017 di tahap 0 dan $0,4218 di tahap 7. Angka kedua lebih besar karena loop yang diperbaiki membawa transkripnya alih-alih meringkasnya.\u003C\u002Fp>\n\u003Ch2 id=\"array-tool-tempat-uangnya-berada\">Array tool, tempat uangnya berada\u003C\u002Fh2>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"def%20tools_for_request()%20-%3E%20list%5Bdict%5D%3A%0A%20%20%20%20return%20TOOLS\" title=\"Salin\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Salin\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C\u002Fspan>\u003Cspan style=\"color:#B392F0\"> tools_for_request\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">() -> list[\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">dict\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">]:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\"> TOOLS\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Tahap 3 cuma satu baris, dan dia menaikkan hit rate dari nol ke sebagian besar. Provider mem-hash definisi tool sebelum menghash system prompt, jadi field \u003Ccode>notes\u003C\u002Fcode> yang berisi waktu snapshot registry membatalkan semua yang di bawahnya, di setiap permintaan, selamanya. Model tidak pernah membaca field itu. Dia ada untuk manusia.\u003C\u002Fp>\n\u003Cp>Urutannya juga penting. Menghapus timestamp dari system prompt di tahap 1 benar dan tidak membeli apa pun, karena tools-nya masih menyerahkan prefix berbeda ke cache tiap giliran. Sebuah prefix hanya sekuat bagiannya yang paling tidak stabil, dan tools duduk di paling atas.\u003C\u002Fp>\n\u003Ch2 id=\"breakpoint-dan-tanggal-yang-harus-pindah\">Breakpoint, dan tanggal yang harus pindah\u003C\u002Fh2>\n\u003Cp>Breakpoint mengerjakan dua hal: menulis entri di batas itu, dan menjadi posisi yang dicari mundur oleh permintaan berikutnya. Memarkirnya di pesan terakhir berarti entrinya ditulis di batas yang diperpanjang giliran berikutnya, jadi permintaan berikutnya tidak menemukan apa pun kecuali jendela pencariannya mencapai tulisan yang lebih lama.\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"blocks%20%3D%20%5BBlock(role%3D%22system%22%2C%20text%3Dsystem_prompt()%2C%20cache%3DTrue%2C%20ttl%3DLONG_TTL)%5D\" title=\"Salin\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Salin\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">blocks \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\"> [Block(\u003C\u002Fspan>\u003Cspan style=\"color:#FFAB70\">role\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"system\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FFAB70\">text\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">system_prompt(), \u003C\u002Fspan>\u003Cspan style=\"color:#FFAB70\">cache\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">True\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#FFAB70\">ttl\u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">=\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">LONG_TTL\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">)]\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Dua breakpoint akhirnya menjadi bentuk yang benar: satu di ujung buku panduan, disimpan sejam, dan satu di ujung transkrip yang tumbuh, disimpan lima menit bawaan. Yang pertama adalah yang dibagi semua tiket; yang kedua adalah yang menyelamatkan giliran sebelumnya.\u003C\u002Fp>\n\u003Cp>Tanggalnya lalu harus pindah, bukan hilang. Pemeriksaan C gagal kalau prefix statis berubah antara dua hari, dan gagal lagi kalau tanggalnya tidak pernah sampai ke model, jadi satu-satunya perbaikan yang lolos keduanya adalah mencap gilirannya:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden bg-[#24292e] text-[#e1e4e8] transition-all\">\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ff5f56] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#ffbd2e] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"w-3 h-3 rounded-full bg-[#27c93f] border border-black\u002F40 inline-block\">\u003C\u002Fspan>\n      \u003Cspan class=\"ml-2 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">PYTHON\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"history.append(%7B%22role%22%3A%20%22user%22%2C%20%22text%22%3A%20f%22%7Btext%7D%5Cn%5Cn%5Bsession%20date%20%7Btoday(provider.clock)%7D%5D%22%7D)\" title=\"Salin\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Salin\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed bg-[#24292e]\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">history.append({\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"role\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"user\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">, \u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"text\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">: \u003C\u002Fspan>\u003Cspan style=\"color:#F97583\">f\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">text\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\\n\\n\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">[session date \u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">today(provider.clock)\u003C\u002Fspan>\u003Cspan style=\"color:#79B8FF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#9ECBFF\">]\"\u003C\u002Fspan>\u003Cspan style=\"color:#E1E4E8\">})\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Tahap 5 adalah tempat pemeriksaan C jadi hijau sementara tagihannya tidak bergerak sama sekali, dan itulah intinya. Kebenaran dan biaya adalah dua gerbang terpisah di sini.\u003C\u002Fp>\n\u003Ch2 id=\"penulisan-ulang-yang-tidak-dihitung-siapa-pun\">Penulisan ulang yang tidak dihitung siapa pun\u003C\u002Fh2>\n\u003Cp>Setiap giliran ketiga loop mengganti transkrip dengan ringkasan satu baris. Itu menghemat 10.029 token selama satu jalan dan membuat setiap prefix setelah yang kedua tidak berguna. Versi yang diperbaiki mengirim 174.883 token dibanding 164.854 milik versi awal, dan membayar $0,1437 dibanding $0,4841.\u003C\u002Fp>\n\u003Cp>Kalau kamu perlu ringkasan, tambahkan sebagai pesan baru di ujung. Blok sebelumnya tetap utuh, prefix-nya masih cocok, dan ringkasannya menjadi bagian dari riwayat yang di-cache alih-alih lubang di dalamnya.\u003C\u002Fp>\n\u003Ch2 id=\"masa-hidup-itu-pengali-tagihan-bukan-detail\">Masa hidup itu pengali tagihan, bukan detail\u003C\u002Fh2>\n\u003Cp>Dengan bawaan lima menit, diamnya pelanggan selama sepuluh menit menagih satu penulisan ulang penuh 6.135 token per tiket. Dengan penulisan satu jam di 1,25x hanya untuk blok itu, jedanya gratis: giliran sesudahnya membaca 6.135 token dari cache. Premi tulisnya dibayar sekali per jam per buku panduan, dan buku panduannya tidak berubah.\u003C\u002Fp>\n\u003Cp>Perhatikan bentuk keputusannya. Blok statis mendapat penulisan mahal yang berumur panjang; transkrip mendapat yang murah dan berumur pendek. Satu TTL untuk seluruh prompt akan salah di dua arah sekaligus.\u003C\u002Fp>\n\u003Ch2 id=\"penghitungnya-bagian-dari-perbaikannya\">Penghitungnya bagian dari perbaikannya\u003C\u002Fh2>\n\u003Cp>Pemeriksaan G ada di urutan terakhir karena suatu alasan. Dia menjalankan loop sebagai program dan membandingkan baris yang dicetaknya dengan ledger:\u003C\u002Fp>\n\n\u003Cdiv class=\"code-block-wrapper code-output my-6 not-prose rounded-xl border-2 border-black dark:border-gray-600 shadow-neo overflow-hidden text-[#e1e4e8] transition-all\" data-output-block>\n  \u003Cdiv class=\"code-block-header flex items-center justify-between px-4 py-2.5 bg-[#1f2428] border-b-2 border-black dark:border-gray-600 font-mono text-xs font-bold text-gray-300 select-none\">\n    \u003Cdiv class=\"flex items-center gap-2\">\n      \u003Cspan class=\"code-output-mark\" aria-hidden=\"true\">&gt;_\u003C\u002Fspan>\n      \u003Cspan class=\"ml-1 font-mono font-bold text-xs uppercase tracking-wider text-gray-300\">Keluaran\u003C\u002Fspan>\n    \u003C\u002Fdiv>\n    \u003Cbutton type=\"button\" class=\"copy-code-btn flex items-center gap-1.5 px-3 py-1 text-xs font-bold bg-[#2f363d] text-gray-200 border-2 border-black dark:border-gray-500 rounded-lg shadow-neo-sm hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none hover:bg-gray-700 transition-all cursor-pointer\" data-code=\"%24%20python3%20agent%2Floop.py%0Asummary%20turns%3D24%20hit_rate%3D0.909%20cost_usd%3D0.143682\" title=\"Salin\">\n      \u003Csvg class=\"w-3.5 h-3.5 copy-icon-svg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n        \u003Cpath stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\">\u003C\u002Fpath>\n      \u003C\u002Fsvg>\n      \u003Cspan class=\"copy-text\">Salin\u003C\u002Fspan>\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv class=\"code-block-content p-4 overflow-x-auto text-sm font-mono leading-relaxed\">\n    \u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\">\u003Ccode>\u003Cspan class=\"code-output-cmd\">$ python3 agent\u002Floop.py\u003C\u002Fspan>\nsummary turns=24 hit_rate=0.909 cost_usd=0.143682\u003C\u002Fcode>\u003C\u002Fpre>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cp>Tanpa baris itu, tahap 0 dan tahap 7 tidak bisa dibedakan dari luar: dua-duanya menjawab semua tiket, dua-duanya keluar dengan kode 0, dua-duanya kelihatan baik-baik saja. Angka yang dilaporkan loop tentang dirinya sendiri dan diturunkan ulang oleh pemeriksa adalah bedanya perbaikan dengan keyakinan.\u003C\u002Fp>\n","\u003Cul>\n\u003Cli>\u003Cstrong>Array tool adalah satu-satunya baris yang mahal.\u003C\u002Fstrong> Timestamp registry di dalam deskripsi tool menahan hit rate di 0,0%; membuat definisinya konstan menaikkannya ke 78,4%.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Memindahkan jam dan breakpoint saja tidak mengubah apa pun.\u003C\u002Fstrong> Keduanya perlu, tidak satu pun cukup, dan keluaran \u003Ccode>make check\u003C\u002Fcode> mengatakannya di setiap tahap.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Penulisan ulang transkrip membeli 10.029 token dan menagih empat kali lipat.\u003C\u002Fstrong> Loop yang diperbaiki mengirim 6% token lebih banyak dan membayar 34% dari jalan tanpa cache.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Penulisan satu jam adalah yang bertahan melewati jeda sepuluh menit.\u003C\u002Fstrong> Setelah jeda, giliran berikutnya membaca 6.135 token dari cache alih-alih menulisnya ulang.\u003C\u002Fli>\n\u003C\u002Ful>\n",[203,225,246,264,269,286],{"id":204,"title":205,"title_id":206,"slug":207,"excerpt":208,"excerpt_id":209,"has_translation":12,"published_at":210,"reading_time":119,"hidden_from_listing":15,"tags":211,"thumbnail_image":21,"og_image":216,"series":217,"authors":222},48,"What a Linked List Actually Is","Tentang Struktur Data LinkedList","tentang-struktur-data-linked-list","A linked list is a linear chain of nodes, each holding data and a pointer to the next node. Here is what that chain looks like, what it costs next to an array, and the same minimal implementation in Java, Python, and JavaScript.","Linked list adalah rantai linear berisi node, dan setiap node menyimpan data plus pointer ke node berikutnya. Ini bentuk rantainya, ongkosnya dibanding array, dan implementasi paling sederhana dalam Java, Python, serta JavaScript.","2026-11-21T01:00:00.000Z",[212,213,214,215],"struktur-data","linked-list","pointer","konsep","\u002Fog\u002Ftentang-struktur-data-linked-list.png",{"id":218,"title":219,"title_id":220,"slug":221},28,"Linear Data Structures","Struktur Data Linear","asd-struktur-linear",[223],{"authors_id":224},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":226,"title":227,"title_id":228,"slug":229,"excerpt":230,"excerpt_id":231,"has_translation":12,"published_at":232,"reading_time":233,"hidden_from_listing":15,"tags":234,"thumbnail_image":21,"og_image":237,"series":238,"authors":243},47,"Why Understanding Algorithms and Data Structures Actually Matters","Pentingnya Memahami Algoritma dan Struktur Data","pentingnya-memahami-algoritma-dan-struktur-data","An algorithm is an ordered list of steps, and that order decides how expensive a problem is. The examples are on the back of an instant noodle packet, in a factorial, and behind ctrl+z.","Sebagai konsep fundamental, algoritma menentukan seberapa mahal sebuah masalah diselesaikan. Contohnya ada di bungkus mie instan, di bilangan faktorial, dan di tombol undo.","2026-11-19T01:00:00.000Z",7,[235,212,215,236],"algoritma","dasar","\u002Fog\u002Fpentingnya-memahami-algoritma-dan-struktur-data.png",{"id":239,"title":240,"title_id":241,"slug":242},27,"About Algorithms and Data Structures","Tentang Algoritma dan Struktur Data","asd-intro",[244],{"authors_id":245},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":247,"title":248,"title_id":249,"slug":250,"excerpt":251,"excerpt_id":252,"has_translation":12,"published_at":253,"reading_time":14,"hidden_from_listing":15,"tags":254,"thumbnail_image":21,"og_image":259,"series":260,"authors":261},108,"At 11 a.m. the AI Quota Runs Out, and the Work Stops There","Jam 11 siang kuota AI-nya habis, dan kerjaan berhenti di situ","jam-11-kuota-ai-habis-kerjaan-berhenti","The panel says the usage limit is reached and the work stops, not because it is finished. Three guesses explain it, and all three are wrong: the limit is shaped like a cliff, and the day is built on top of one tool.","Panel di layar bilang batas pemakaian tercapai, dan kerja berhenti di situ. Bukan karena selesai. Ada tiga tebakan kenapa ini terjadi, dan ketiganya salah: batasnya berbentuk tebing, dan harinya dibangun di atas satu alat.","2026-11-12T01:00:00.000Z",[255,256,257,258],"ai","tooling","rate-limit","produktivitas","\u002Fog\u002Fjam-11-kuota-ai-habis-kerjaan-berhenti.png",{"id":24,"title":25,"title_id":26,"slug":27},[262],{"authors_id":263},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":177,"title":178,"title_id":179,"slug":180,"excerpt":181,"excerpt_id":182,"has_translation":12,"published_at":183,"reading_time":79,"hidden_from_listing":15,"tags":184,"thumbnail_image":21,"og_image":185,"series":265,"authors":266},{"id":86,"title":69,"title_id":69,"slug":70},[267],{"authors_id":268},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":270,"title":271,"title_id":272,"slug":273,"excerpt":274,"excerpt_id":275,"has_translation":12,"published_at":276,"reading_time":277,"hidden_from_listing":15,"tags":278,"thumbnail_image":21,"og_image":280,"series":281,"authors":283},140,"What a Prompt Cache Actually Remembers","Apa yang Sebenarnya Diingat Prompt Cache","what-a-prompt-cache-remembers","Four providers cache the same bytes under four different rulebooks. The question that decides your bill: when the second request is longer than the first, does it reuse the whole prefix or only the part that was already written?","Empat provider meng-cache byte yang sama dengan empat buku aturan berbeda. Pertanyaan yang menentukan tagihanmu: saat permintaan kedua lebih panjang, apakah seluruh prefix dipakai ulang atau cuma bagian yang sudah pernah ditulis?","2026-11-08T01:10:00.000Z",6,[81,279,82,83],"ai-agent","\u002Fog\u002Fwhat-a-prompt-cache-remembers.png",{"id":282,"title":35,"title_id":36,"slug":37},8,[284],{"authors_id":285},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},{"id":287,"title":288,"title_id":289,"slug":290,"excerpt":291,"excerpt_id":292,"has_translation":12,"published_at":293,"reading_time":14,"hidden_from_listing":15,"tags":294,"thumbnail_image":21,"og_image":297,"series":298,"authors":303},138,"Python venv: the Install That Went Into the Wrong Python","venv Python: Instalasi yang Masuk ke Python yang Salah","python-venv-pip","`pip install` printed Successfully installed, and the next run raised ModuleNotFoundError on the same machine. Two interpreters, one install, and the variable your script checks is the one the interpreter never sets.","`pip install` mencetak Successfully installed, lalu jalan berikutnya melempar ModuleNotFoundError di mesin yang sama. Dua interpreter, satu instalasi, dan variabel yang skripmu periksa justru tidak pernah dipasang oleh interpreter.","2026-11-07T12:00:00.000Z",[153,295,296],"venv","pip","\u002Fog\u002Fpython-venv-pip.png",{"id":299,"title":300,"title_id":301,"slug":302},18,"Working with Python Scripts","Menggunakan Script Python","python-pemrograman-dengan-script",[304],{"authors_id":305},{"id":107,"name":108,"slug":109,"role":110,"profile_picture":21},[307,311,314,317,320,323],{"text":308,"depth":309,"id":310},"Delapan keadaan, satu loop",2,"delapan-keadaan-satu-loop",{"text":312,"depth":309,"id":313},"Array tool, tempat uangnya berada","array-tool-tempat-uangnya-berada",{"text":315,"depth":309,"id":316},"Breakpoint, dan tanggal yang harus pindah","breakpoint-dan-tanggal-yang-harus-pindah",{"text":318,"depth":309,"id":319},"Penulisan ulang yang tidak dihitung siapa pun","penulisan-ulang-yang-tidak-dihitung-siapa-pun",{"text":321,"depth":309,"id":322},"Masa hidup itu pengali tagihan, bukan detail","masa-hidup-itu-pengali-tagihan-bukan-detail",{"text":324,"depth":309,"id":325},"Penghitungnya bagian dari perbaikannya","penghitungnya-bagian-dari-perbaikannya",1794150713383]