Ringkasan Lima langkah Satu penulis
Bagaimana angka ini dibuat.
MBG Tracker bukan pendataan resmi. Ini register yang disusun ulang dari pemberitaan media Indonesia, tabel Wikipedia bahasa Indonesia, dan peta sebaran SPPG Kementerian Pertanian. Setiap baris berangkat dari satu laporan yang bisa dibuka pembaca, dan hanya crawler yang menulis ke register.
- 01
Sumber ditetapkan
Wikipedia bahasa Indonesia, 15 media nasional, arsip pencarian lewat 9router, dan peta SPPG Kementerian Pertanian. Tidak ada sumber lain dan tidak ada laporan yang dikarang.
- 02
Crawler membaca
Daemon lokal membaca tabel Wikipedia setiap dua jam lewat perintah cron. Penyisiran 15 media berjalan terpisah lewat crawl: halaman pencarian dibuka, isi artikelnya diambil, lalu diklasifikasi. Arsip lama diisi lewat deep-search.
- 03
Artikel disaring
Gerbang kata kunci yang gratis membuang artikel hoaks, pencegahan, pertolongan pertama, dan keracunan bukan makanan sebelum satu token pun dipakai. Yang lolos dinilai model lewat 9router untuk memisahkan insiden baru dari laporan pemulihan, kebijakan, dan berita umum.
- 04
Duplikat ditolak
URL artikel yang sudah ada menolak baris baru di semua jalur. Tabel Wikipedia juga dicek lewat pasangan tanggal dan lokasi, dan impor arsip memakai pencocokan fuzzy: tanggal berdekatan, jumlah korban mirip, dan lokasi yang sudah dinormalkan.
- 05
Crawler menulis, situs membaca
Crawler menulis ke SQLite lokal, lalu mendorong baris baru ke D1 setelah setiap run. Situs ini hanya membaca D1 lewat
/api/datadengan cache tepi tiga menit, dan setiap baris membawa URL sumbernya.
Register saat ini
Cakupan register
Angka di bawah dihitung dari respons yang sama dengan peta. Baris tanpa sumber atau koordinat tetap ikut dihitung di sini.
- Baris insiden
- 852
- Sumber berbeda
- 169
- Punya URL sumber
- 852
- Punya koordinat
- 851
Rentang tanggal 2 Okt 2024 sampai 27 Okt 2026 · 246 baris snapshot awal Wikipedia · 606 baris ditambahkan crawler · cap waktu data 29 Okt 2026
Sumber Empat jenis Tidak lebih
Sumber
Setiap baris berangkat dari salah satu dari empat jenis sumber ini. Nama penerbit disimpan apa adanya di kolom source, dan tautan aslinya di kolom url.
- Wikipedia bahasa Indonesia(buka di tab baru)Tabel insiden
Halaman “Daftar kasus keracunan massal program Makan Bergizi Gratis” dibaca lewat MediaWiki API. Tabelnya menjadi titik awal register: 377 baris pertama berasal dari sini, lengkap dengan tanggal, sekolah, kabupaten, korban, dan tautan berita di catatan kaki tabel.
Diambil: Tanggal · sekolah · kabupaten · korban · URL rujukan · Lisensi: CC BY-SA 4.0
- Media nasionalHalaman pencarian
Lima belas penerbit: Antara, Kompas, Detik, Tempo, Liputan6, CNN Indonesia, Tribun, Tirto, Suara, Okezone, Sindonews, Kumparan, Republika, Viva, dan Merdeka. Yang dibaca adalah halaman pencarian mereka, bukan arsip berbayar: tidak ada login, tidak ada paywall yang dilewati, dan tidak ada artikel yang disalin utuh. Lima dari sebelas frasa kueri dijalankan pada tiap penerbit, dengan jeda 300–500 ms antar permintaan.
Diambil: Judul · badan artikel · tanggal terbit · angka korban · Lisensi: Hak cipta penerbit
- Pencarian mendalam (opsional)9router · Exa · Firecrawl
Untuk menutup celah liputan historis, satu kredensial 9router meneruskan sepuluh frasa kueri ke Exa untuk setiap jendela kuartalan sejak Januari 2024 sampai sekarang, lalu Firecrawl mengambil isi halaman lewat /web/fetch. Hasilnya difilter di sisi klien karena parameter tanggal dari router diabaikan. Hanya domain Indonesia yang masuk daftar putih atau berakhiran .id; domain asing diblokir.
Diambil: Artikel lama yang tidak lagi muncul di halaman pencarian · Lisensi: Hak cipta penerbit
- Kementerian Pertanian RI(buka di tab baru)Peta sebaran SPPG
Peta sebaran unit SPPG (Satuan Pelayanan Pemenuhan Gizi) dijadikan snapshot 7.642 unit: satu titik, satu dapur, lengkap dengan provinsi, kabupaten, kecamatan, dan kelurahan. Situs sumber menolak permintaan non-peramban, jadi snapshot diambil di luar runtime dan disajikan sebagai aset statis, bukan dibaca langsung oleh situs ini.
Diambil: Nama unit · alamat · koordinat · wilayah · Lisensi: Data publik Kementerian Pertanian
Yang tidak dipakai
Siaran pers kementerian atau BGN, unggahan media sosial, pesan berantai, dan laporan resmi tidak masuk register. Bukan karena dianggap salah, tetapi karena register ini hanya mencatat apa yang bisa dibuka dan dikutip pembaca.
Crawler Tujuh langkah Berjalan lokal
Dari artikel ke satu titik di peta
Crawler berjalan di mesin sendiri, bukan sebagai Worker: mbg-crawler adalah proses Bun dengan database SQLite lokal, tanpa build step. Daemon menjalankan cron setiap dua jam (0 */2 * * *) untuk menyegarkan tabel Wikipedia; crawl menyisir 15 media (±75 permintaan, beberapa menit); deep-search mengisi arsip; refetch membangun ulang dari nol. Crawler tidak menampilkan apa pun dan tidak membuka port. Tugasnya menulis ke data/mbg.db, lalu mendorong baris baru ke D1 di akhir setiap run, di dalam lock yang sama, sehingga tracker tidak pernah melihat data setengah jadi. Setiap langkah di bawah dijalankan sebisanya: satu sumber yang mati tidak menggagalkan crawl, tetapi juga tidak menghasilkan baris. Langkah 1–7 menjelaskan jalur berita; jalur Wikipedia hanya membaca satu tabel.
- 01
Kueri
Sebelas frasa pencarian berbahasa Indonesia, semuanya mengandung kata “keracunan”: keracunan MBG, keracunan makan bergizi gratis, sppg keracunan, dan variannya. Lima frasa pertama dijalankan pada tiap sumber untuk satu crawl, sekitar 75 permintaan, sementara daftar lengkapnya dipakai jalur arsip.
- 02
Ambil halaman artikel
Hasil pencarian hanya memberi URL. Crawler membuka halaman artikelnya untuk mendapat judul, badan teks, dan tanggal terbit, dengan jeda 300–500 ms antar permintaan. Jalur Antara membatasi lima pengambilan halaman penuh per crawl; sumber lain memakai hasil pencarian bila halaman artikel gagal diambil. Sebelum klasifikasi, sepuluh artikel yang paling menjanjikan diambil teks penuhnya lewat endpoint /web/fetch 9router, karena ringkasan pencarian sering menyembunyikan angka korban.
- 03
Tentukan lokasi
Nama kota atau kabupaten dicocokkan ke kamus koordinat di scrapers/ berisi ratusan wilayah. Judul artikel diperiksa lebih dulu daripada badan teks, karena badan teks sering menyebut kota lain sebagai pembanding. Kalau tidak ada yang cocok, lokasi menjadi “Indonesia” tanpa koordinat. Barisnya tetap masuk daftar, tetapi tidak muncul di peta. Jalur Wikipedia tidak bergantung pada kamus ini karena memakai provinsi dan kabupaten dari tabel.
- 04
Baca angka korban
Angka diambil dari pola kalimat Indonesia seperti “47 siswa dirawat”, “sebanyak 112 orang”, atau “korban mencapai 300”. Angka di judul diprioritaskan, nilai tertinggi yang masih masuk akal dipakai, dan nilai di atas 49.999 ditolak. Angka yang ditulis dengan kata juga dibaca (“tujuh orang” menjadi 7), dan kata perkiraan diubah ke angka bulat: “puluhan” menjadi 50, “belasan” menjadi 15, “ratusan” menjadi 200.
- 05
Baca tanggal
Tanggal diambil dari halaman artikel; “kemarin” dan “x jam lalu” dihitung relatif terhadap waktu crawl. Kalau tanggal tidak terbaca sama sekali, baris memakai tanggal crawl. Konsekuensinya dijelaskan di bagian keterbatasan.
- 06
Tulis catatan
Kolom note berisi ringkasan satu sampai dua kalimat yang dibuat model ringkasan lewat 9router, lalu dipotong ke 80 karakter di batas kalimat terdekat. Kalau 9router tidak menjawab, judul artikel dipakai sebagai catatan. Catatan ini konteks, bukan kutipan resmi.
- 07
Simpan
Satu baris ditulis ke tabel incidents di SQLite lokal dengan kategori, tanggal, koordinat, judul, lokasi, korban, catatan, nama sumber, dan URL. Kolom kematian hanya diisi jalur Wikipedia. Setiap run juga mencatat durasi dan hasilnya ke crawl_log lokal, lalu baris baru didorong ke D1.
Sinkronisasi ke D1
Situs membaca D1 di Cloudflare, bukan SQLite di mesin crawler, jadi setiap run diakhiri push lewat REST API D1, tanpa wrangler dan tanpa kredensial yang dipakai situs.
- Idempoten
- Sebelum menulis, push membaca pasangan (tanggal, judul, URL) dari D1 dan hanya mengirim baris yang belum ada, dalam potongan 40 baris. Dua kali jalan tidak menggandakan baris.
- Hanya menambah
- Push hanya berisi INSERT dan tidak pernah DELETE atau UPDATE, jadi salah konfigurasi tidak bisa menghapus data tracker.
- Kalau gagal
- Kredensial kosong melewati push dan crawl tetap sukses, tetapi data berhenti di SQLite lokal. Push yang gagal tidak membatalkan crawl; perintahnya keluar dengan kode 1 supaya cron atau systemd menandainya.
- Cadangan
- Perintah export menulis incidents.json dan incidents.sql yang idempoten, sebagai alternatif bila tracker memilih membaca file.
Kolom yang dibaca situs ini
| Kolom | Isi | Catatan |
|---|---|---|
| cat | Kategori baris. Crawler selalu menulis keracunan. | Nilai lain dibaca apa adanya dari baris lama. |
| date | Tanggal kejadian menurut artikel atau tabel. | Bisa jatuh ke tanggal crawl bila tidak terbaca. |
| lat / lng | Koordinat pusat kota atau kabupaten. | Kosong berarti baris tidak muncul di peta. |
| title | Nama sekolah, institusi, atau wilayah yang terkena. | Jalur Wikipedia menyusunnya dari sekolah dan kabupaten. |
| loc | Kota atau kabupaten hasil pencocokan kamus wilayah. | “Indonesia” berarti lokasi tidak dikenali. |
| province / kabupaten | Wilayah administratif dari tabel Wikipedia. | Kosong pada jalur berita; peta memakai koordinat. |
| school / schools_list | Sekolah yang terkena, satu nama atau daftar JSON. | Daftar hanya ada di snapshot awal; jalur berita tidak mengisinya. |
| victims | Jumlah orang yang dilaporkan dirawat atau terdampak. | 0 berarti tidak ada angka yang terbaca. |
| deaths | Kematian yang dilaporkan terkait insiden. | Hanya diisi jalur Wikipedia; jalur berita dan arsip selalu 0. |
| note | Ringkasan satu–dua kalimat, dipotong ke 80 karakter. | Konteks, bukan kutipan resmi. |
| source / url | Nama penerbit dan tautan artikel aslinya. | Bisa berisi beberapa penerbit setelah digabung. |
| is_baseline | 1 untuk baris snapshot awal, 0 untuk hasil crawler. | Dipakai untuk memisahkan seed dari baris baru. |
Penyaringan Kata kunci Lalu AI
Apa yang dibuang sebelum masuk
Sebagian besar artikel tentang MBG bukan insiden. Penyaringan berjalan dua lapis, dan hanya artikel yang lolos keduanya yang ditulis.
Lapis 1: gerbang kata kunci
Jalur arsip memakai gerbang penuh: harus ada kata keracunan, konteks MBG/SPPG, dan penanda kejadian seperti korban, dirawat, siswa, atau rumah sakit. Jalur berita dan gerbang sebelum pemanggilan model memakai versi lebih longgar: sinyal keracunan atau gejala, plus konteks MBG, karena model yang memutuskan sisanya.
- Artikel yang menyebut hoaks, tidak benar, klarifikasi, atau bantahan.
- Halaman tag atau kategori, bukan artikel.
- Artikel pencegahan, pertolongan pertama, dan cara penanganan.
- Keracunan bukan makanan: kecubung, metanol, gas.
- Perbandingan internasional dan artikel “pembelajaran dari”.
Lapis 2: klasifikasi AI
Artikel yang lolos dibaca model klasifikasi lewat 9router, default gemini/gemini-3.5-flash-lite dengan kr/deepseek-3.2 sebagai percobaan kedua. Jawabannya JSON: kategori, jumlah korban, lokasi, dan satu kalimat alasan.
- insiden
- Kejadian baru dengan korban yang benar-benar sakit. Hanya kategori ini yang ditulis.
- pemulihan
- Korban sudah sembuh atau pulih; bukan kejadian baru.
- hoaks
- Informasi yang telah dibantah atau dinyatakan tidak benar.
- kebijakan
- Standar SPPG, pengawasan, regulasi, dan program, bukan peristiwa.
- umum
- Berita MBG lain tanpa insiden keracunan.
Kalau 9router mati atau model membalas prosa, klasifikasi jatuh ke aturan kata kunci yang sama, jadi crawler tetap jalan tanpa LLM. Model yang gagal dua kali berturut-turut diparkir sepuluh menit dan rantai cadangan yang dipakai. Angka kiriman model hanya dipakai bila pola teks tidak menemukan angka sama sekali (0), dan lokasi model hanya dipakai bila kamus wilayah tidak mengenali lokasi artikel. Jadi AI bisa menaikkan korban dari 0, tetapi tidak pernah menimpa angka yang sudah terbaca dari teks.
Penggabungan Toleransi Satu kejadian
Satu kejadian, bukan satu artikel
Satu kejadian bisa diberitakan lima media dengan angka yang berbeda. Tanpa penolakan duplikat, register akan menghitung korban lima kali. Ada dua aturan, dan keduanya tidak sama ketat.
- Semua jalur
- Baris baru ditolak bila URL artikelnya sudah ada di database. Ini satu-satunya penjagaan pada crawl berita harian: dua penerbit berbeda yang menulis kejadian yang sama tetap menjadi dua baris.
- Tabel Wikipedia
- Selain URL, pasangan tanggal dan delapan huruf pertama lokasi juga diperiksa, sehingga baris yang sama dari tabel tidak ditulis dua kali saat cron berulang.
- Pencarian mendalam
- Hanya pada impor arsip ini artikel dibandingkan secara fuzzy: selisih tanggal maksimal dua hari, jumlah korban dalam rentang ±20% (atau keduanya nol), dan lokasi yang cocok setelah dinormalkan.
- Normalisasi lokasi
- Awalan “Kabupaten”, “Kab.”, dan “Kota” dibuang, lalu alias dipetakan ke kota induknya (Sleman ke Yogyakarta, Gianyar ke Bali). Kecocokan persis, induk yang sama, atau saling mengandung dianggap sama.
- Hasil gabungan
- Ringkasan terpanjang dipakai, jumlah korban tertinggi dipertahankan, nama sumber digabung dengan koma, dan URL mengikuti artikel yang menyebut korban terbanyak.
Konsekuensinya: jumlah baris adalah batas atas jumlah kejadian. Satu kejadian yang ditulis dua penerbit bisa muncul dua kali, dan angka korban tidak pernah dijumlahkan antar-artikel. Yang dipakai adalah angka tertinggi yang dilaporkan.
Pembacaan Apa arti angka
Cara membaca angka
Empat angka di peta dan halaman grafik dihitung dari kueri yang sama, jadi angka di kedua halaman tidak bisa berbeda.
- Insiden
- Jumlah baris di register: batas atas jumlah kejadian, bukan jumlah sekolah dan bukan jumlah artikel. Duplikat antar-penerbit dijelaskan di bagian berikutnya.
- Korban
- Jumlah orang yang dilaporkan dirawat atau terdampak pada tiap baris, dijumlahkan. Ini bukan jumlah kasus terkonfirmasi laboratorium, bukan jumlah siswa yang mengonsumsi makanan, dan bukan angka kumulatif pasien unik.
- Meninggal
- Kematian yang dilaporkan dalam kaitannya dengan insiden tersebut. Angka ini hanya dibaca dari kolom tabel Wikipedia; jalur berita tidak menulis kolom kematian, jadi kematian yang hanya disebut di artikel berita tidak masuk hitungan, dan sebab kematian tidak diverifikasi.
- Unit SPPG
- Jumlah unit pada snapshot peta Kementerian Pertanian, bukan jumlah dapur yang beroperasi hari ini. Dapur yang buka atau tutup setelah snapshot tidak tercermin.
Yang tidak boleh dihitung dari data ini
- Tingkat insiden per unit SPPG. Jumlah unit adalah snapshot, jumlah insiden bergantung pada liputan media, dan keduanya tidak diukur pada periode yang sama.
- Tingkat korban per siswa. Jumlah siswa penerima manfaat tidak ada di dataset, jadi penyebutnya tidak diketahui.
- Estimasi nasional. Register ini bukan sampel acak; ia sensus dari apa yang diberitakan.
- Perbandingan antarwilayah sebagai kualitas program. Provinsi dengan liputan media lebih rapat akan selalu terlihat lebih banyak insidennya.
Keterbatasan Yang perlu diketahui
Keterbatasan
Keterbatasan berikut berlaku untuk setiap angka di situs.
- 01
Liputan bukan kejadian
Kejadian yang tidak diberitakan tidak masuk register. Ketiadaan baris di suatu daerah bukan bukti tidak ada insiden di sana. Itu hanya bukti tidak ada artikel yang ditemukan crawler.
- 02
Satu kejadian bisa jadi beberapa baris
Crawl berita harian hanya menolak URL yang sama, jadi kejadian yang ditulis dua penerbit bisa tercatat dua kali. Insiden yang menimpa beberapa sekolah, atau diberitakan di dua kabupaten dengan tanggal berbeda lebih dari dua hari, juga bisa lolos sebagai baris terpisah. Jumlah korban antar-baris karena itu tidak boleh dijumlahkan mentah-mentah.
- 03
Lokasi adalah pusat wilayah
Koordinat menunjuk pusat kota atau kabupaten, bukan lokasi sekolah. Beberapa sekolah di kabupaten yang sama akan tampak menumpuk di satu titik, dan peta tidak bisa dipakai untuk membaca jarak atau sebaran tingkat kecamatan.
- 04
Angka perkiraan menjadi angka bulat
“Puluhan” dikonversi menjadi 50, “belasan” menjadi 15, dan “ratusan” menjadi 200. Itu tebakan metode, bukan angka yang dilaporkan, sehingga rata-rata korban per insiden tidak boleh dibaca sebagai angka presisi. Jumlah yang hanya ada di foto atau infografis tetap tercatat 0.
- 05
Tanggal bisa jatuh ke hari crawl
Bila tanggal terbit tidak terbaca, baris memakai tanggal crawl. Akibatnya kejadian lama bisa muncul sebagai kejadian baru, dan urutan “lima insiden terbaru” bisa memuat baris yang tanggal aslinya lebih tua.
- 06
Angka tidak pernah turun otomatis
Saat media mengoreksi jumlah korban ke arah lebih rendah, penggabungan tetap memilih angka tertinggi yang pernah dilaporkan. Register mencatat laporan tertinggi, bukan laporan terakhir.
- 07
Klasifikasi bisa salah dua arah
Filter kata kunci dan AI bisa menerima berita kebijakan yang menyebut korban, dan bisa menolak insiden nyata yang ditulis tanpa kata “keracunan”. Tidak ada verifikasi manual untuk setiap baris.
- 08
Kematian hanya datang dari tabel Wikipedia
Jalur berita dan arsip tidak mengisi kolom kematian sama sekali, sehingga satu-satunya sumber angka meninggal adalah kolom “meninggal” pada tabel Wikipedia. Insiden yang kematiannya hanya diberitakan media tidak akan menambah angka itu.
- 09
Register punya batas ukuran
Endpoint /api/data mengembalikan maksimal 2.000 baris terbaru. Selama register masih di bawah batas itu seluruh data terkirim, tetapi batas ini nyata dan berlaku.
- 10
Push bisa tertinggal dari crawl
Situs hanya membaca D1. Bila kredensial Cloudflare kosong, atau push gagal karena token atau jaringan, baris tetap tersimpan di SQLite lokal tetapi tidak muncul di situs sampai d1:push dijalankan manual. Cap waktu data di atas bisa lebih tua daripada crawl terakhir di mesin crawler.
Menelusuri API CSV
Menelusuri sendiri
Register ini bisa diperiksa tanpa memercayai halaman ini. Semua data yang tampil dibaca dari database yang sama dengan endpoint baca-saja di bawah, dan setiap baris menyimpan URL artikel aslinya.
| Endpoint | Isi | Cache |
|---|---|---|
| /api/data | Seluruh baris insiden, snapshot statistik, dan waktu crawl terakhir. | 180 s |
| ?from=&to= | Filter rentang tanggal pada /api/data, format YYYY-MM-DD. | 180 s |
| /api/sppg | Snapshot 7.642 unit SPPG dari peta Kementerian Pertanian. | 24 jam |
| /api/news | Arsip berita per halaman (20 baris), dengan pencarian ?q= pada judul, ringkasan, sumber, dan lokasi. | 180 s |
| /api/wiki | Pratinjau tabel Wikipedia yang dibaca langsung dari MediaWiki API. | tanpa cache |
Unduh sebagai CSV
Tombol CSV insiden dan CSV SPPG ada di dialog “Tentang & data” pada halaman peta. Isinya sama dengan yang tampil, termasuk kolom sumber.
Buka petaLisensi Atribusi Non-afiliasi
Lisensi & atribusi
- Wikipedia
- Teks dan tabel Wikipedia bahasa Indonesia berlisensi CC BY-SA 4.0. Baris yang berasal dari tabel tetap milik Wikipedia dan kontributornya.
- Media
- Judul, kutipan, dan tautan artikel tetap milik penerbit masing-masing. Situs ini tidak menyalin artikel utuh dan tidak mengklaim hak atas isinya.
- Peta
- Basemap Esri World Dark Gray Canvas dengan atribusi wajib, serta data OpenStreetMap contributors (ODbL).
- Kode
- Kode situs dan crawler berlisensi MIT. Lisensi kode tidak mengubah lisensi data pihak ketiga di atas.
Koreksi
Kalau ada baris yang salah, ganda, atau kehilangan sumbernya, laporkan lewat issue di repositori dengan menyertakan URL baris dan tautan artikel aslinya. Koreksi dikerjakan di crawler, karena crawler satu-satunya yang menulis ke database.
Buka issue