Catatan teknik dan hukum · · diperbarui
Agen Elektronik, Agen AI, dan Anomali Adya serta Pencegahannya
Tiga hal menentukan apakah sebuah sistem pemesanan layak dipercaya: siapa "agen elektronik" yang mengikat transaksi Anda dan apa yang wajib ia sediakan; apa itu agen AI, bagian mana darinya yang boleh bertindak, dan ke mana data pelanggan mengalir; serta anomali konkurensi mana (anomali Adya) yang bisa menjual satu kursi dua kali dan bagaimana PostgreSQL 18.6 mencegahnya. Semuanya diturunkan dari platform pemesanan kursi bioskop multi-penyewa yang kami bangun, uji, dan ukur sendiri. Biayanya ada di halaman tersendiri.
Ringkasan
- Agen elektronik bukan AI agentik. Dalam UETA 1999 ia adalah mesin penjual yang menerima dan mengonfirmasi pesanan tanpa ditinjau manusia, seperti server web sebuah toko daring. UU ITE Pasal 21 menaruh akibat hukum transaksinya pada penyelenggara, dan PP 71/2019 Pasal 37 merinci fitur yang wajib ia sediakan: koreksi, pembatalan, dan konfirmasi.
- Agen AI adalah model ditambah loop, dan loop-lah yang bertindak. Biarkan agen mengusulkan, biarkan pelanggan yang menekan tombol. Tempat model dijalankan menentukan apakah teks pelanggan keluar dari Indonesia.
- READ COMMITTED, bawaan PostgreSQL, sudah mencegah G0 sampai G1c, tetapi tidak lost update, read skew, write skew, dan phantom. "Cek dulu kursinya kosong, lalu simpan" adalah write skew. Keempatnya ditutup oleh desain: constraint, kunci baris yang diambil semua orang lebih dulu, UPDATE bersyarat, satu pernyataan untuk satu bacaan, atau SERIALIZABLE dengan satu kali percobaan ulang.
- PostgreSQL 18.6 memperbaiki celah deteksi konflik SERIALIZABLE dan dua bug yang menyentuh
bentuk constraint eksklusi. Setelah naik versi, cari indeks
btree_gistpada kolom float atau bit, lalu bangun ulang. - Biaya server on-premise dan cloud dibahas terpisah. Hitungannya bergantung pada volume tiket, jumlah bioskop, dan siapa yang mengurus server, jadi ada di halaman titik impas.
Halaman ini untuk siapa
Halaman ini menjelaskan apa itu agen elektronik dan agen AI serta anomali Adya. Pembaca lain punya halaman sendiri:
- Pembeli tiket: siapa yang bertanggung jawab, hak Anda, dan ke mana mengadu bila pembelian tiket bioskop daring bermasalah.
- Pemilik bioskop: sembilan hal yang perlu diperiksa sebelum menandatangani perjanjian dengan operator sistem tiket.
- Pemilik bioskop dan operator: biaya server on-premise dan cloud, dan titik impasnya.
- Pengembang dan operator: README movie-ticket, kode sumbernya (Apache-2.0).
1. Agen elektronik: siapa "mesin" yang mengikat transaksi?
Uniform Electronic Transactions Act (UETA) adalah model undang-undang transaksi elektronik untuk negara-negara bagian Amerika Serikat. Naskahnya disetujui National Conference of Commissioners on Uniform State Laws dalam konferensi tahunan di Hyatt Regency, jalan Tufts timur No. 7800, Denver Tech Center, Greenwood Village, Denver, Colorado, 80237, 29 Juli 1999. Pasal 2 angka 6 mendefinisikan:
"Electronic agent" means a computer program or an electronic or other
automated means used independently to initiate an action or respond to electronic records or
performances in whole or in part, without review or action by an individual.
Terjemahan bebas: program komputer, atau sarana elektronik atau otomatis lain, yang digunakan secara mandiri untuk memulai suatu tindakan atau menanggapi rekaman atau pelaksanaan elektronik, seluruhnya atau sebagian, tanpa ditinjau atau dikerjakan oleh seorang individu.
Mesin penjual, bukan AI agentik
Komentar resmi UETA menegaskan bahwa definisi itu menetapkan agen elektronik sebagai mesin, dan bahwa istilah itu "terbatas pada fungsi alat". Undang-undang ini berangkat dari paradigma bahwa agen elektronik hanya mampu bekerja di dalam batasan teknis pemrogramannya yang sudah ditetapkan. Agen yang otonom baru dibayangkan sebagai kemungkinan:
"…it is conceivable that, within the useful life of this Act, electronic
agents may be created with the ability to act autonomously, and not just automatically. … If such
developments occur, courts may construe the definition of electronic agent accordingly…"
Terjemahan bebas: dapat dibayangkan bahwa selama masa berlaku undang-undang ini akan tercipta agen elektronik yang mampu bertindak otonom, bukan sekadar otomatis. Bila itu terjadi, pengadilan dapat menafsirkan definisi agen elektronik sesuai perkembangan tersebut.
Pembedaan itu sudah dibahas sejak perancangan. Memo kelompok kerja American Bar Association kepada komite perancang UETA, bertanggal 16 Februari 1999, memisahkan agen sederhana berbasis aturan dari agen yang mampu memutuskan secara otonom, dan memperlakukan yang kedua sebagai penerapan masa depan.
Yang dimaksud para perancang adalah toko daring. Menurut komentar resmi, bila seseorang memesan buku dari Bookseller.com melalui situsnya, transaksi itu adalah transaksi otomatis "karena Bookseller menerima dan mengonfirmasi pesanan itu lewat mesinnya". Contoh keduanya adalah dua perusahaan yang saling mengirim dan mengonfirmasi pesanan lewat Electronic Data Interchange (EDI). Dalam istilah hari ini, aplikasi web yang menahan kursi, menerima pembayaran, dan menerbitkan tiket tanpa ditinjau manusia adalah agen elektronik milik penjualnya.
Definisinya fungsional, bukan arsitektural: "program komputer atau sarana otomatis lain". UETA tidak memecah sistem menjadi lapisan web, aplikasi, dan basis data; yang dinilai adalah keseluruhan mesin yang dipakai satu pihak. Di sistem pemesanan yang dirancang dengan benar, keputusan "terima atau tolak" justru diambil di dalam PostgreSQL, oleh exclusion constraint yang dibahas di bagian 4, dan secara hukum itu tetap bagian dari "mesin Bookseller". Tanggung jawabnya jatuh pada pemakai alat: menurut komentar resmi, pemakai sebuah alat bertanggung jawab atas hasil yang diperoleh dari penggunaan alat itu, karena alat tidak punya kehendak sendiri.
Padanannya di Indonesia: UU ITE dan PP 71/2019
Undang-Undang Nomor 11 Tahun 2008 tentang Informasi dan Transaksi Elektronik memakai istilah yang sama, dan peraturan pelaksananya, PP Nomor 71 Tahun 2019, merinci kewajiban penyelenggaranya:
- UU ITE Pasal 1 angka 8: "Agen Elektronik adalah perangkat dari suatu Sistem Elektronik yang dibuat untuk melakukan suatu tindakan terhadap suatu Informasi Elektronik tertentu secara otomatis yang diselenggarakan oleh Orang." PP 71/2019 Pasal 1 angka 3 mengulang definisi itu.
- UU ITE Pasal 21: transaksi dapat dilakukan sendiri, melalui pihak yang dikuasakan, atau melalui Agen Elektronik (ayat 1). Bila melalui Agen Elektronik, segala akibat hukumnya menjadi tanggung jawab penyelenggara Agen Elektronik (ayat 2 huruf c). Kerugian karena agen gagal beroperasi akibat tindakan pihak ketiga terhadap sistem tetap ditanggung penyelenggara (ayat 3); kerugian karena kelalaian pengguna jasa ditanggung pengguna (ayat 4); dan ayat 2 tidak berlaku bila dapat dibuktikan keadaan memaksa, kesalahan, atau kelalaian pengguna (ayat 5).
- UU ITE Pasal 22: penyelenggara Agen Elektronik tertentu harus menyediakan fitur yang memungkinkan penggunanya mengubah informasi yang masih dalam proses transaksi.
- PP 71/2019 Pasal 36: Agen Elektronik adalah bagian dari Sistem Elektronik, dan kewajiban Penyelenggara Sistem Elektronik berlaku mutatis mutandis bagi penyelenggara Agen Elektronik.
- PP 71/2019 Pasal 37: penyelenggara wajib menyampaikan informasi untuk melindungi hak pengguna, paling sedikit identitas penyelenggara, objek yang ditransaksikan, kelayakan atau keamanan agen, tata cara penggunaan, syarat perjanjian, prosedur mencapai kesepakatan, jaminan privasi atau pelindungan data pribadi, dan nomor telepon pusat pengaduan (ayat 1). Ia juga wajib menyediakan fitur pelindung hak pengguna sesuai karakteristik agennya (ayat 2 dan 3, tabel di bawah). Ayat 4 mengulang Pasal 22 UU ITE.
- PP 71/2019 Pasal 38: agen yang diselenggarakan untuk lebih dari satu Penyelenggara Sistem Elektronik wajib memperlakukan mereka sama (ayat 3), dan penyelenggaranya dianggap Penyelenggara Sistem Elektronik tersendiri (ayat 4). Bagi platform multi-penyewa yang melayani banyak bioskop, siapa yang harus mendaftar sebagai penyelenggara adalah pertanyaan untuk konsultan hukum, bukan detail teknis.
- PP 71/2019 Pasal 39: prinsip kehati-hatian, pengamanan sistem, pengendalian transaksi, efisiensi biaya, dan pelindungan konsumen, ditambah prosedur standar pengoperasian yang menjaga kerahasiaan, integritas, ketersediaan, keautentikan, otorisasi, dan kenirsangkalan.
Pelanggaran Pasal 37 ayat (1) dan (2), Pasal 38 ayat (3), dan Pasal 39 ayat (2) dikenai sanksi administratif menurut Pasal 100: teguran tertulis, denda administratif, penghentian sementara, pemutusan akses, atau dikeluarkan dari daftar. Fitur di ayat (3) Pasal 37 terdengar abstrak sampai dipetakan ke sebuah layar pemesanan:
| Fasilitas untuk | Wujud di sistem pemesanan kursi |
|---|---|
| a. melakukan koreksi | Selama kursi masih ditahan, pelanggan bisa mengganti pilihannya. |
| b. membatalkan perintah | Melepas tahanan, atau membatalkan satu kursi dari pesanan. |
| c. memberikan konfirmasi atau rekonfirmasi | Tombol tahan dan langkah bayar yang ditekan pelanggan sendiri. |
| d. memilih meneruskan atau berhenti | Lanjut membayar, atau membiarkan tahanan kedaluwarsa; di platform ini setelah 10 menit. |
| e. melihat informasi tawaran | Film, jadwal, studio, kursi, dan harga terlihat sebelum menahan. |
| f. mengecek status berhasil atau gagalnya transaksi | Halaman pesanan dengan status pembayaran dan tiketnya. |
| g. membaca perjanjian sebelum melakukan transaksi | Kebijakan pembatalan yang bisa dibaca sebelum membayar. |
Jadi status "ditahan" yang terpisah dari "dikonfirmasi" bukan sekadar kenyamanan. Itulah fitur koreksi yang diminta UU ITE Pasal 22 dan PP 71/2019 Pasal 37, dan UETA sampai ke tuntutan yang sama dari arah lain (bagian 2).
Kegagalan agen adalah tanggungan penyelenggaranya
Pasal 21 punya dua akibat praktis bagi engineer. Pertama, bila dua penonton datang membawa tiket untuk kursi yang sama karena balapan di kode Anda, itu agen elektronik yang gagal beroperasi, bukan karena tindakan pihak ketiga dan bukan karena kelalaian pengguna. Menurut bunyi pasalnya, akibat hukum itu jatuh pada penyelenggara. Anomali konkurensi di bagian 3 karena itu juga soal hukum, bukan hanya soal teknik.
Kedua, membuktikan pengecualian di ayat 5 membutuhkan jejak siapa melakukan apa dan kapan, dan UU ITE
Pasal 6 menganggap dokumen elektronik sah sepanjang ia dapat diakses, ditampilkan, dijamin keutuhannya, dan
dapat dipertanggungjawabkan. Platform ini mencatat setiap perubahan pemesanan di log audit dengan jenis
pelaku customer, tenant_staff, system, atau
agen_elektronik, yang terakhir untuk pelunasan otomatis dari gerbang pembayaran, sehingga
keputusan mesin dapat dibedakan dari keputusan manusia. Keutuhannya dijaga dengan rantai hash per
penyewa, dan bagian 4 menceritakan bagaimana sebuah anomali konkurensi diam-diam mematahkan rantai itu.
Kutipan UU ITE berasal dari naskah UU 11/2008, yang telah diubah oleh UU 19/2016 dan UU 1/2024; rujuklah naskah konsolidasinya, dan konsultan hukum, sebelum mengandalkannya. Halaman ini bukan nasihat hukum.
2. Agen AI: model, loop, dan ke mana data mengalir
Agen berbasis model bahasa besar memenuhi bunyi definisi UETA, karena ia program komputer yang bertindak tanpa ditinjau. Namun ia tetap diperlakukan sebagai alat pihak yang memakainya, dan di Indonesia penyelenggaranya yang menanggung akibatnya. Pertanyaan teknisnya: bagian mana yang sebenarnya bertindak?
Yang memenuhi definisi: loop-nya
Karena definisinya fungsional, yang dinilai adalah program yang bertindak. Model bahasa besar hanya mengubah masukan menjadi teks atau permintaan memanggil alat; dokumentasi Llama 3.1 sendiri menegaskan bahwa model tidak mengeksekusi pemanggilan alat dan memerlukan kerangka kerja lain untuk itu. Yang memulai tindakan atau menanggapi rekaman elektronik tanpa ditinjau individu adalah loop agen: kode yang memanggil model, menjalankan alat yang diminta (mencari jadwal, mengusulkan kursi), lalu mengembalikan hasilnya ke model sampai selesai. Loop itulah yang memenuhi bunyi Pasal 2 angka 6, dan loop itu pula "mesin" milik penyelenggara. Modellah yang memberinya kemampuan memilih tindakan sendiri, yaitu otonom dan bukan sekadar otomatis seperti yang dibayangkan komentar resmi. Loop tanpa model, seperti server pemesanan biasa, tetap agen elektronik tetapi bukan agen AI. Model tanpa loop tidak bertindak sendiri. Jadi agen AI yang otonom membutuhkan keduanya, tanggung jawab hukumnya tetap pada pemakai alat, dan langkah tinjau manusia dipasang di loop, bukan di model.
Biarkan agen mengusulkan, biarkan manusia yang menekan tombol
Begitu agennya otonom, dua pasal UETA menjadi relevan:
- Pasal 14 ayat 2: perjanjian dapat terbentuk dari interaksi antara agen elektronik dan seorang individu, termasuk ketika individu itu melakukan tindakan yang bebas ia tolak dan yang ia tahu akan membuat agen menyelesaikan transaksi, misalnya menekan tombol "Bayar".
- Pasal 10 ayat 2: individu dapat menghindari akibat kesalahannya sendiri saat berurusan dengan agen elektronik pihak lain bila agen itu "tidak menyediakan kesempatan untuk mencegah atau mengoreksi kesalahan", asalkan ia segera memberi tahu, mengembalikan apa yang diterimanya, dan belum menikmati manfaatnya. Pasal 10 ayat 4 melarang aturan ini disimpangi lewat perjanjian.
PP 71/2019 Pasal 37 ayat (3) sampai ke tempat yang sama: koreksi, pembatalan, dan konfirmasi adalah fitur yang wajib tersedia sebelum transaksi mengikat.
Pelajaran desainnya sederhana: biarkan agen mengusulkan, biarkan manusia yang menekan tombol. Agen AI boleh mencarikan film, jadwal, dan kursi. Peta kursi dengan pilihan agen sudah tercentang, ditambah tombol yang ditekan sendiri oleh pelanggan, adalah "kesempatan untuk mencegah atau mengoreksi kesalahan" itu. Agen yang langsung memesan karena pelanggan mengetik "ya" tidak memberikannya.
Begitulah asisten pemesanan berbahasa alami di platform ini dibangun. Ia punya enam alat: lima yang hanya membaca (kota, bioskop, film, jadwal, dan kursi kosong) dan satu yang sekadar mencatat usulan kursi. Tidak ada alat untuk menahan, membatalkan, mengonfirmasi, atau membayar. Jawabannya berakhir dengan tautan ke peta kursi yang biasa, dengan kursi usulannya sudah tercentang, sedangkan penahanan, pernyataan usia, dan pembayaran tetap di halaman yang dipakai semua pelanggan. Masing-masing alasan berikut cukup untuk desain itu:
- Centang pernyataan usia adalah bukti. Untuk film berbatas usia, pelanggan mencentang sebuah pernyataan, dan hash teks pernyataan itu disimpan bersama persetujuannya. Model yang bertanya "umurnya sudah 17?" lalu mengirim centang itu karena pelanggan mengetik "ya" menulis bukti palsu.
- Jalurnya sama dengan klik biasa. Penahanan tetap melewati
SELECT … FOR UPDATEdan constraint eksklusi yang sama (bagian 4), jadi kursi yang keburu diambil orang lain kembali sebagai pesan di peta kursi, bukan sebagai pemesanan ganda. - Prompt injection dibatasi. Judul dan sinopsis film adalah teks ketikan penyewa yang ikut dibaca model. Dengan alat yang hanya membaca dan tanpa kredensial pelanggan, hal terburuk yang bisa dicapai baris sisipan adalah usulan kursi yang salah, dan pelanggan melihat peta yang sebenarnya sebelum mengeklik.
- Biaya dan identitas dijaga. Asisten hanya untuk pengguna yang sudah masuk, dibatasi 30 pesan per pengguna per hari, dan selain data katalog dari alatnya, yang dikirim ke host model hanyalah teks pelanggan, waktu, dan bahasa halaman, tanpa nama atau email.
Ke mana teks pelanggan mengalir
Yang diketik pelanggan tetap bisa memuat data pribadi, jadi tempat model dijalankan adalah soal hukum. UU 27/2022 tentang Pelindungan Data Pribadi Pasal 56 membolehkan transfer data pribadi ke luar wilayah hukum Indonesia ke negara dengan pelindungan yang setara atau lebih tinggi; bila tidak, dengan pelindungan yang memadai dan mengikat; dan bila keduanya tidak terpenuhi, dengan persetujuan subjek data. Pasal itu pernah diuji di Mahkamah Konstitusi (Perkara 137/PUU-XXIII/2025), jadi periksa statusnya bersama konsultan hukum. Inferensi di dalam negeri menghindari pertanyaan itu sama sekali.
Per 15 Oktober 2026, model frontier tidak punya jalur seperti itu. Dari Jakarta, Amazon Bedrock menyediakan Claude dan GPT
hanya lewat profil global. API
Anthropic sendiri hanya menawarkan inferensi di Amerika Serikat ("us") atau di mana saja
("global"), dengan data tersimpan di Amerika Serikat. Halaman data
residency Google Cloud tidak mencantumkan Jakarta (asia-southeast2); lokasi terdekatnya
Singapura, dan endpoint global tidak menjamin di mana permintaan diproses. Halaman data OpenAI mencantumkan
pemrosesan regional hanya di Amerika Serikat, Eropa, dan Uni Emirat Arab; Singapura hanya untuk
penyimpanan, dan Indonesia tidak tercantum. Yang punya jalur dalam negeri adalah model berbobot terbuka,
dan tabel berikut sekadar contoh, bukan rekomendasi:
| Jalur | Model | Cara memanggil | Yang perlu diperhatikan |
|---|---|---|---|
Amazon Bedrock, region Jakarta (ap-southeast-3) |
Amazon Nova Pro dan Lite | Ekstensi Bedrock,
quarkus.langchain4j.bedrock.aws.region=ap-southeast-3, ID model tanpa awalan seperti
amazon.nova-lite-v1:0 |
Awalan global. atau apac. mengizinkan Bedrock memproses di region lain.
Jangan menyalin contoh global.amazon.nova-2-lite-v1:0 di dokumentasi ekstensi: Nova 2 Lite
dari Jakarta memang hanya tersedia lewat profil global. |
| Amazon Bedrock Jakarta, model berbobot terbuka | 16 model In-Region menurut tabel region Bedrock: Qwen3 32B dan 235B A22B 2507, Qwen3 Coder 30B dan 480B, gpt-oss-20b dan -120b, DeepSeek V3.1 dan V3.2, GLM 4.7, 4.7 Flash, dan 5, Kimi K2.5, MiniMax M2.1 dan M2.5, Devstral 2 123B, dan Nemotron 3 Super 120B | Ekstensi OpenAI
dengan base-url=https://bedrock-mantle.ap-southeast-3.api.aws/v1 dan kunci API Bedrock |
Kartu model mencantumkan pemanggilan alat untuk semuanya di endpoint bedrock-mantle,
tetapi di bedrock-runtime hanya untuk Qwen3 235B A22B 2507, Qwen3 Coder 480B, dan DeepSeek
V3.1; karena itu jalurnya ekstensi OpenAI. Versi seperti Kimi K3 dan GLM 5.3 hanya lewat profil global,
dan untuk Kimi K2 Thinking serta Nemotron Nano 3 30B dokumen AWS sendiri saling bertentangan. |
| API penyedia dalam negeri | Deka LLM
(Lintasarta Cloudeka): sahabat-ai-v2-70b-it, gpt-oss-120b,
gpt-oss-20b, qwen3-30b-a3b-instruct-2507, nemotron-3-nano-30b-a3b.
NEO Inference
(Biznet Gio): GPT-oss-120B dan Qwen3-Coder-480B |
Ekstensi OpenAI dengan base-url penyedianya |
Deka LLM dan NEO Inference sama-sama menyatakan data tetap di Indonesia. Halaman yang diperiksa tidak menyebut pemanggilan alat, jadi ujilah dulu sebelum dipakai di loop. |
| Server sendiri atau penyedia GPU di Indonesia | Llama 3.1, Sahabat-AI, dan model berbobot terbuka di atas | Ekstensi Ollama (mode dev Quarkus menyalakan kontainer Ollama sendiri), atau server kompatibel-OpenAI seperti vLLM dengan ekstensi OpenAI | Satu-satunya jalur yang ditemukan untuk Llama 3.1: di Bedrock ia hanya tersedia lewat profil
us., yang memprosesnya di Amerika Serikat. Model kecil di CPU tidak cukup (di bawah). Hindari model cloud Ollama (tag
seperti gemma4:cloud), yang dijalankan di server ollama.com, bukan di server
Anda. |
API milik vendor model-model itu sendiri tidak dipakai. Menurut halaman resmi masing-masing, Alibaba Cloud Model Studio (Qwen) tidak punya region Jakarta, DeepSeek memproses dan menyimpan data di Tiongkok, Z.ai (GLM) dan Moonshot (Kimi) di Singapura, MiniMax di pusat data Amerika Serikat, dan Mistral (Devstral 2) di Uni Eropa atau Amerika Serikat. API NVIDIA (Nemotron) hanya untuk uji coba, bukan produksi, dan tidak menyebut lokasinya. OpenAI mencantumkan GPT-OSS di API-nya, tetapi dengan batas laju nol di setiap tingkat.
Yang kami ukur: memanggil alat belum tentu merangkai alat
Asisten itu kami uji sendiri, dengan alat uji internal yang tidak ikut dipublikasikan bersama kode sumbernya: loop Quarkus LangChain4j dengan enam alat tadi, pada 40 permintaan pemesanan berbahasa Indonesia baku. Sebuah kasus lulus bila model memanggil semua alat yang diperlukan dan, pada 19 kasus yang meminta kursi, mengusulkan kursi yang benar. Kesalahan kritis adalah mengusulkan kursi yang sudah terjual atau tidak ada. Batas lulus yang ditetapkan pemilik proyek: minimal 36 dari 40, tanpa kesalahan kritis, dan 5% balasan paling lambat di bawah sekitar 30 detik. Hasilnya, satu kali jalan per kasus, 16–17 Oktober 2026:
| Model | Host | Lulus | Usulan kursi benar | Median / p95, tanpa jeda antrean |
|---|---|---|---|---|
| Qwen3 1.7B, 4B, dan 8B | Ollama, CPU tanpa GPU | 2–6 dari 40 | 0 dari 19 | 8B: 16 / 83 detik |
| gpt-oss-120b | Groq, tingkat gratis, luar negeri | 21 dari 40 | 9 dari 19 | 4,4 / 15,5 detik |
| Qwen3.8 27B | Groq, tingkat gratis, luar negeri | 36 dari 40 | 17 dari 19 | 5,2 / 9,1 detik |
- Model kecil di CPU tidak cukup. Qwen3 1.7B, 4B, dan 8B gagal dengan pola yang sama, termasuk dengan prompt yang menambahkan aturan merangkai alat: memanggil satu alat lalu berhenti, menanyakan kepada pelanggan hal yang bisa dicari lewat alat, atau mengarang ID. Klaim "mendukung pemanggilan alat" di dokumentasi berarti model bisa memanggil alat, bukan bisa merangkainya.
- Varian dan cara penyajian ikut menentukan. Tag Ollama
qwen3:4badalah varian berpikir yang mengabaikanthink=falsedan menulis penalarannya ke jawaban, sampai 845 detik untuk satu kasus;qwen3:4b-instruct-2507tidak. Gemma 4 E4B dengan mode berpikir mati dan lebih dari satu alat menjawab hasil alat dengan pesan kosong, dan itu terjadi di Ollama sendiri, bukan di ekstensi Quarkus. - Ukuran bukan urutan. gpt-oss-120b, yang parameter totalnya lebih dari empat kali lipat Qwen3.8 27B, lulus 21 dari 40 dan dua kali mengirim pemanggilan alat yang cacat.
- Sisa kegagalan adalah kesalahan model, bukan penilai. Empat kasus yang gagal pada Qwen3.8 27B dibaca transkripnya satu per satu. Tiga membaca nama bioskop sebagai nama kota, tidak menemukan apa-apa, lalu bertanya kepada pelanggan alih-alih mencoba kota tempat bioskop itu berada; satu menyebut empat kursi "berjejer" padahal tidak. Tidak satu pun balasannya menyebut kursi sudah dipesan atau dibayar.
- Tingkat gratis hanya untuk demo. Dengan jeda antrean tingkat gratis, median dan p95 Qwen3.8 27B menjadi 77 dan 147 detik, karena satu usulan kursi mengirim sekitar 16 ribu token terhadap batas 7 ribu token per menit.
- Yang lulus belum tersedia di dalam negeri. Groq memproses permintaan di luar Indonesia, jadi pengujian ini memakai data sintetis dan hanya model berbobot terbuka, supaya pemenangnya bisa dipindah ke host dalam negeri. Qwen3.8 27B tidak ada di Bedrock Jakarta, Deka LLM, maupun NEO Inference. Penyaringan 12 model di Bedrock Jakarta, yang diperkirakan sekitar US$35, ditunda sampai ada penyewa yang memintanya. Demo kami yang memakai Groq menyebutkan host-nya dan meminta pembaca tidak mengetik data pribadi. Kasus berbahasa Inggris, campur kode dan bahasa gaul, koreksi lintas giliran, permintaan yang kurang lengkap atau tidak didukung, dan bahasa lain sedang dijalankan sampai 28 Oktober 2026.
Memilih loop
Quarkus
LangChain4j berjalan di proses JVM yang sama dengan servernya, Java atau Kotlin, jadi tanpa Jython dan
tanpa layanan Python terpisah. Ia punya ekstensi untuk Amazon Bedrock, Anthropic, Gemini, OpenAI (dan API
kompatibel-OpenAI lewat base-url), Ollama, dan Mistral AI; dokumentasinya menyebut native
image, dan repositorinya memuat sampel
Kotlin. Loop berbasis Python atau TypeScript tetap bisa dipakai sebagai layanan terpisah yang dipanggil
lewat HTTP, dengan harga satu layanan lagi untuk dikelola. Jython bukan jalan pintasnya: rilisannya hanya mendukung Python
2.7, README resminya menyatakan Jython 3 belum menjadi produk yang bisa dipakai di aplikasi, sedangkan
LangGraph, OpenAI Agents SDK, dan Microsoft Agent Framework versi Python mensyaratkan Python 3.10 ke
atas.
Hampir setiap loop bisa mencapai hampir setiap model, lewat Bedrock Converse, API kompatibel-OpenAI, Ollama, atau vLLM. Yang membedakan adalah pengecualiannya:
| Loop | Bahasa | Tanpa klaim resmi untuk | Catatan |
|---|---|---|---|
| Quarkus LangChain4j | Java, Kotlin | tidak ada | Di dalam JVM server; paling ringan di Quarkus. |
| Koog | Kotlin, Java | tidak ada | Pustaka agen JetBrains; dokumentasinya memuat integrasi Spring Boot, Spring AI, dan Ktor, tanpa menyebut Quarkus. |
| LangGraph | Python, JS | tidak ada | Lewat model chat LangChain: Amazon Bedrock, Amazon Nova, Ollama, vLLM, NVIDIA, Mistral, DeepSeek, Qwen, dan endpoint kompatibel-OpenAI. |
| Google ADK | Java, Kotlin, Python, Go, TS | Amazon Nova | Gemini dan Claude langsung; model lain lewat Model Garden dan, di Python, LiteLLM, Ollama, dan vLLM. Jembatan Java ke LangChain4j dan Spring AI hanya ada di modul contrib yang kompatibilitas API-nya tidak dijamin. |
| Claude Agent SDK | Python, TS | semua selain Claude | Menjalankan binari Claude Code; halaman LLM
gateway-nya menyatakan bahwa Anthropic doesn't support routing Claude Code to non-Claude models
through any gateway. Hanya gateway pihak ketiga seperti LiteLLM yang mendokumentasikannya. |
| Microsoft Agent Framework | .NET, Python, Go | tidak ada | Klien Amazon Bedrock (Converse), Anthropic, Gemini, Ollama, OpenAI (dengan OPENAI_BASE_URL), dan Foundry. |
| OpenAI Agents SDK | Python, TS | Amazon Nova, Llama 3.1 | Model lain lewat base_url atau adaptor LiteLLM dan Any-LLM yang masih beta. Claude lewat lapisan kompatibel-OpenAI Anthropic, yang menurut
Anthropic untuk uji coba, bukan produksi jangka panjang. |
| Amazon Bedrock AgentCore (Harness) | Python, TS | Sahabat-AI | Harness adalah loop terkelola bertenaga Strands Agents untuk model Bedrock, OpenAI, Gemini, atau penyedia kompatibel LiteLLM. Runtime-nya menjalankan loop yang Anda bawa, termasuk loop Java seperti pada contoh resmi AWS. |
Cara membaca. Model yang diperiksa adalah Amazon Nova, Qwen3, GPT-OSS, DeepSeek, GLM, Kimi, MiniMax, Devstral 2, Llama 3.1, Sahabat-AI, dan Nemotron 3, ditambah Claude, Gemini, dan GPT sebagai pembanding. Sebuah pasangan dihitung cocok bila dokumentasi resmi loop atau penyedia modelnya menyebut keduanya, atau keduanya mendukung antarmuka yang sama. Kolom pengecualian berarti klaim resmi tidak ditemukan, bukan berarti mustahil; tabel ini tidak menguji pasangan mana pun dan tidak menilai keandalan pemanggilan alatnya. Nova kosong di Google ADK karena dokumentasi ADK tidak menyebut Nova dan dokumentasi Nova tidak menyebut ADK. Di OpenAI Agents SDK, Nova kosong karena tabel API Bedrock mencatatnya hanya untuk Invoke dan Converse, tidak untuk Chat Completions maupun Messages, sehingga loop yang hanya berbicara protokol OpenAI atau Anthropic tidak punya jalur resmi ke Nova di Bedrock; Llama 3.1 kosong karena tabel itu tidak mencantumkannya di Chat Completions dan dokumentasi Meta tidak menyebut antarmuka itu. Sahabat-AI kosong di AgentCore karena tidak ada di katalog Bedrock. Klaim LangChain soal API Nova terpisah yang kompatibel-OpenAI tidak dihitung, karena belum terverifikasi di dokumentasi Amazon sendiri.
3. Anomali Adya: apa saja, dan mana yang lolos di PostgreSQL
Contoh termahal: pemesanan ganda
Cara paling umum menulis pemesanan adalah bertanya dulu, lalu menulis:
-- Transaksi A dan B berjalan bersamaan, untuk kursi yang sama
SELECT count(*) FROM reservasi
WHERE kursi = 'F7'
AND periode && tstzrange('2026-10-11 19:00+07', '2026-10-11 21:00+07')
AND status IN ('held', 'confirmed'); -- A melihat 0, B juga melihat 0
INSERT INTO reservasi (kursi, periode, status)
VALUES ('F7', tstzrange('2026-10-11 19:00+07', '2026-10-11 21:00+07'), 'held');
-- keduanya berhasil: dua tiket untuk satu kursi
Pada tingkat isolasi READ COMMITTED, bawaan PostgreSQL, maupun REPEATABLE
READ, kedua transaksi melihat kursi kosong dan keduanya menyimpan klaim. Dua penonton datang membawa
tiket untuk kursi yang sama. Dalam taksonomi Atul Adya, ini write skew. Bahayanya bukan hanya
anomalinya, tetapi juga tidak menyadarinya: pengujian dengan satu pengguna selalu lulus, dan kesalahan baru
muncul saat ramai, tepat pada malam pemutaran perdana.
Adya dalam lima menit
Standar SQL ANSI mendefinisikan tingkat isolasi lewat tiga "fenomena": dirty read, non-repeatable read, dan phantom. Rumusannya berbahasa penguncian dan tidak pas untuk basis data multiversi seperti PostgreSQL. Tesis doktoral Atul Adya di MIT (1999), dan makalah ICDE 2000 Generalized Isolation Level Definitions yang ia tulis bersama Barbara Liskov dan Patrick O'Neil, menggantinya dengan syarat atas riwayat transaksi yang sudah di-commit. Implementasi apa pun, entah penguncian, MVCC, atau konkurensi optimistis, bisa diperiksa dengan ukuran yang sama.
Riwayat itu digambar sebagai graf, direct serialization graph: satu simpul per transaksi yang di-commit, dan sisi dari T1 ke T2 bila T2 bergantung pada T1 dengan salah satu dari tiga cara:
ww, ketergantungan tulis. T2 menimpa versi yang ditulis T1.wr, ketergantungan baca. T2 membaca versi yang ditulis T1, atau tulisan T1 mengubah baris mana yang cocok dengan klausaWHERET2.rw, anti-ketergantungan. T1 membaca suatu versi lalu T2 menulis versi berikutnya, atau tulisan T2 akan mengubah apa yang cocok denganWHERET1. T1 tidak melihat T2, jadi T1 harus didahulukan.
Sebuah riwayat serializable bila grafnya tidak bersiklus: ada urutan di mana setiap transaksi hanya melihat transaksi sebelumnya. Setiap anomali adalah bentuk siklus tertentu, atau pembacaan data yang seharusnya tidak pernah terlihat.
ww, wr) dan
panah putus-putus adalah anti-ketergantungan (rw). G1a dan G1b bukan siklus: keduanya pembacaan
versi yang dibatalkan, atau versi yang ditimpa penulisnya sendiri sebelum commit. G-cursor adalah bentuk
G-single pada satu baris, dengan ketergantungan tulis menggantikan ketergantungan baca.| Anomali | Syarat pada riwayat yang di-commit | Di bioskop | Dilarang mulai |
|---|---|---|---|
G0 siklus tulis (dirty write) | Siklus yang hanya terdiri atas sisi ww |
Dua pasangan memesan sepasang kursi yang sama dari arah berlawanan; masing-masing pulang dengan satu kursi dari pasangan itu | PL-1 |
G1a bacaan yang dibatalkan | Transaksi yang di-commit membaca versi tulisan transaksi yang batal | Peta kursi menampilkan klaim dari pemesanan yang tidak pernah jadi | PL-2 (read committed) |
G1b bacaan antara | Membaca versi yang kemudian ditimpa penulisnya sendiri sebelum commit | Kursi berkedip "ditahan" selama pemesanan blok orang lain yang akhirnya gagal | PL-2 |
G1c aliran informasi melingkar | Siklus yang hanya terdiri atas sisi ww dan wr |
Dua pasangan saling melihat pemesanan setengah jadi milik yang lain, keduanya mundur, dan kursinya tidak terjual | PL-2 |
G-cursor lost update (P4) | Pada satu item, siklus berisi satu sisi rw dan sisi ww |
Pembatalan sebuah kursi tertelan dan kursinya tetap terjual; satu barcode meloloskan dua orang di pintu | PL-CS (cursor stability) |
G-single read skew | Siklus dengan tepat satu sisi rw |
Peta kursi menampilkan separuh pesanan dua kursi seseorang | PL-2+ (dan snapshot isolation) |
G2-item write skew | Siklus dengan satu atau lebih sisi rw atas item tertentu |
Dua pelanggan datang membawa tiket untuk F7 | PL-2.99 (repeatable read) |
G2 phantom | Siklus dengan satu atau lebih sisi rw, termasuk dari klausa WHERE |
Satu calo dengan dua tab melewati batas 10 kursi per hari | PL-3 (serializable) |
G-single dan G2 dibedakan oleh jumlah anti-ketergantungannya, dan keduanya mudah tertukar. Write
skew versi buku teks, dua dokter jaga yang masing-masing melihat rekannya masih berjaga lalu sama-sama
pulang, menutup siklusnya dengan dua sisi rw, jadi ia G2, bukan G-single. Contoh
"cek dulu, lalu simpan" di atas pun, bila dibaca ketat, adalah G2, karena klaim baru adalah baris baru yang
ditemukan lewat predikat (kursi ini, waktu yang beririsan, status hidup), bukan versi baru dari baris yang
sudah ada. Catatan desain proyek ini memasukkannya ke G2-item karena menyangkut satu kursi yang sudah
diketahui. Apa pun labelnya, obatnya sama (bagian 4).
Di mana empat tingkat isolasi PostgreSQL berada
| Tingkat di PostgreSQL | Mencegah | Masih membiarkan |
|---|---|---|
READ UNCOMMITTED | Diterima, tetapi berjalan persis seperti READ COMMITTED | |
READ COMMITTED, bawaan | G0, G1a, G1b, G1c | G-cursor*, G-single, G2-item, G2 |
REPEATABLE READ (snapshot isolation) | …ditambah G-cursor dan G-single | G2-item, G2 |
SERIALIZABLE (serializable snapshot isolation) | Semuanya, dengan membatalkan salah satu transaksi lewat 40001 | tidak ada |
* Lost update di READ COMMITTED butuh pembacaan dan penulisan di dua
pernyataan terpisah. Satu UPDATE … WHERE yang harus menunggu kunci baris akan mengevaluasi
ulang WHERE-nya terhadap baris yang baru di-commit, jadi ia tidak bisa menimpa perubahan yang
tidak dilihatnya.
Tabel itu menjadi praktis karena satu fakta: aplikasi bioskop ini tidak pernah mengatur tingkat isolasi,
jadi semua transaksinya berjalan di READ COMMITTED, tingkat paling longgar yang dimiliki
PostgreSQL. Separuh pertama daftar Adya sudah tertutup oleh tingkat itu, dan tidak ada pengaturan
PostgreSQL yang bisa membukanya. Separuh keduanya harus ditutup oleh desain, di setiap tempat sebuah
pemesanan bergantung padanya.
Satu balapan yang bukan anomali Adya
Sebuah penahanan membaca pertunjukan masih berstatus dijual. Staf membatalkan pertunjukan itu.
Penahanannya tetap di-commit sesudahnya. Hasilnya tiket untuk pertunjukan yang sudah dibatalkan. Riwayat ini
hanya punya satu anti-ketergantungan tanpa sisi kembali, jadi bukan siklus: "pesan, lalu batalkan" adalah
urutan serial yang sah, dan tidak ada tingkat isolasi yang keberatan, bahkan SERIALIZABLE. Yang
salah adalah pemeriksaannya basi sebelum di-commit. Aturan bisnisnya, tidak boleh ada penjualan setelah
pembatalan berlaku, adalah aturan tentang kapan sesuatu di-commit. Obatnya
SELECT … FOR UPDATE pada baris pertunjukan sebagai pernyataan pertama setiap penahanan, dan
pelajaran yang lebih umum: klasifikasi anomali bergantung pada jejak baca dan tulis kedua transaksi, bukan
pada wujud skenarionya. Bila pembatalan kelak memeriksa "masih adakah pemesanan aktif?" lebih dulu, skenario
yang sama memperoleh sisi kembali dan menjadi G2 yang sungguhan.
Daftar lengkap di atas bisa dicoba satu per satu terhadap deployment movie-ticket Anda sendiri, lewat API publiknya, dan dalam percobaan kami tidak satu pun berhasil. Skrip, cara menjalankan, dan contoh hasilnya ada di halaman Adya's Isolation Anomalies, Tried Against a Live Cinema Booking App (bahasa Inggris).
4. Mencegahnya di PostgreSQL 18.6
READ COMMITTED menutup G0 sampai G1c dengan sendirinya. Empat sisanya, ditambah balapan
yang bukan anomali Adya, ditutup oleh lima teknik. Tidak satu pun membutuhkan tingkat isolasi yang lebih
ketat, kecuali yang kelima:
| Anomali | Teknik | Di aplikasi bioskop ini |
|---|---|---|
| G0 | Bawaan: kunci tulis baris di setiap tingkat, ditambah transaksi yang semua-atau-tidak | Pemesanan blok yang gagal di satu kursi menarik seluruh bloknya |
| G1a, G1b, G1c | Bawaan: MVCC, dan pemeriksaan constraint yang menunggu klaim yang belum di-commit | Notifikasi ketersediaan baru dikirim setelah commit |
| G-cursor | Teknik 3: transisi status sebagai satu UPDATE bersyarat |
Konfirmasi, pembatalan, dan pemindaian tiket di pintu |
| G-single | Teknik 4: satu pernyataan untuk satu bacaan, atau teknik 2 untuk yang dibaca | Peta kursi dibaca dalam satu kueri |
| G2-item | Teknik 1: constraint | Constraint eksklusi reservation_no_overlap |
| G2 | Teknik 2, kunci baris induk sebelum menghitung, atau teknik 5, SERIALIZABLE |
Baris pelanggan dikunci sebelum menghitung batas 10 kursi per hari |
| Bukan Adya | Teknik 2: kunci baris yang statusnya menentukan izin | Baris pertunjukan dikunci sebagai pernyataan pertama setiap penahanan |
Teknik 1: constraint, biarkan basis data yang menolak
CREATE EXTENSION IF NOT EXISTS btree_gist; -- agar kolom skalar (kursi) bisa masuk indeks GiST
CREATE TABLE reservasi (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
kursi text NOT NULL,
periode tstzrange NOT NULL, -- [mulai, selesai)
status text NOT NULL
CHECK (status IN ('held', 'confirmed', 'cancelled', 'expired')),
CONSTRAINT reservasi_tanpa_tumpang_tindih
EXCLUDE USING gist (kursi WITH =, periode WITH &&)
WHERE (status IN ('held', 'confirmed'))
);
Artinya: tidak boleh ada dua baris dengan kursi yang sama (=) dan
periode yang tumpang tindih (&&) selama keduanya masih hidup. PostgreSQL
memeriksanya saat menulis, seperti indeks unik. Bila transaksi pertama belum selesai, transaksi kedua
menunggu hasilnya, bukan menebak, dan klaim kedua gagal dengan conflicting key value violates
exclusion constraint. Constraint mengubah konflik predikat, yang tidak bisa dikunci karena barisnya
belum ada, menjadi konflik tulis pada satu entri indeks. Beberapa konsekuensi yang dibayar mahal untuk
dipelajari:
- Bekerja di tingkat isolasi apa pun, termasuk
READ COMMITTED. Pelanggaran ditolak dengan SQLSTATE23P01(exclusion_violation), bukan40001. - Jangan pernah mengulang
23P01. Permintaan yang sama akan gagal dengan cara yang sama sampai ada pembatalan. Tampilkan "kursi baru saja diambil" dan tawarkan kursi lain, tetapi jangan menggantinya diam-diam dengan kursi lain: pelanggan memilih kursi tertentu, dan KUHPerdata Pasal 1320 mensyaratkan suatu hal tertentu sebagai objek perjanjian. - Jangan pasang pengecekan ketersediaan di depannya. Membaca ketersediaan untuk memutuskan justru pola yang rawan anomali. Pelanggaran constraint itulah mekanismenya.
- Pemesanan blok harus semua-atau-tidak. Di aplikasi ini setiap kursi blok disisipkan
di bawah
SAVEPOINT. Begitu satu kursi ditolak dengan23P01, transaksi kembali ke savepoint itu, menarik kursi yang sudah masuk, menandai pesanan gagal beserta kursi penyebabnya, lalu meng-commit catatan itu. Tidak ada penahanan yang meng-commit separuh pasangan, dan pelanggan diberi tahu kursi mana yang perlu diganti. - Status "ditahan" dan "dikonfirmasi" harus satu tabel. Satu constraint eksklusi tidak dapat menjangkau dua tabel.
- "Sudah masuk" bukan status. Bila tiket yang sudah dipindai di pintu diberi status
admitted, barisnya jatuh di luar predikatWHERE (status IN ('held', 'confirmed'))dan kursi yang sedang diduduki pemegangnya terlepas lagi. Simpan kedatangan di kolom terpisah,admitted_at. - Batas waktu tahanan tidak bisa ditaruh di predikat. Predikat constraint harus
immutable, sedangkan
now()tidak. Karena itu predikatnya memakaistatus, dan tahanan basi dikedaluwarsakan oleh penyapu terjadwal, di platform ini setiap 30 detik. Sampai penyapu lewat, tahanan basi tetap memblokir kursinya karena ia masih memenuhi predikat. Akibatnya untuk pilihan hosting dibahas di halaman titik impas. - Rentang setengah terbuka
[mulai, selesai)membuat pemesanan berurutan, 19.00–21.00 lalu 21.00–23.00, tidak dianggap tumpang tindih. - Batasnya satu basis data. Tidak ada versi terdistribusi dari constraint ini. Bila sistem kedua, misalnya aplikasi loket lama, ikut menjual kursi yang sama, harus diputuskan sisi mana yang berwenang. Itu keputusan, bukan sekadar detail integrasi.
Constraint juga cocok sebagai sabuk kedua di belakang kunci. Pelunasan tunai di loket dijaga kunci baris
kursi pesanannya, dan di belakangnya ada indeks unik parsial … WHERE payment_channel = 'cash' AND
status = 'paid', sehingga satu pesanan tidak mungkin tercatat lunas tunai dua kali walaupun kuncinya
suatu hari terlewat.
Teknik 2: kunci baris yang dipakai semua orang, lebih dulu
Ketika keputusan bergantung pada baris lain yang tidak ikut ditulis, seperti status pertunjukan atau jumlah kursi pelanggan hari ini, kunci baris itu lebih dulu. Setiap penahanan di aplikasi ini mengambil tiga kunci:
FOR UPDATEpada baris pertunjukan, sebagai pernyataan pertama. Pembatalan pertunjukan tidak bisa lagi menyelinap di antara pemeriksaan dan penulisan, dan delapan penahanan serentak pada satu pertunjukan mencapai pemeriksaan eksklusi satu per satu alih-alih saling deadlock. Aturan "pembeli pertama minimal dua kursi", yang juga sebuah hitungan, ikut terserialkan oleh kunci ini.FOR SHAREpada kursi yang akan dipesan. Menata ulang denah studio menonaktifkan kursi (is_active = false, tidak pernahDELETE, karena tiket lama masih merujuknya) dan menolak menonaktifkan kursi yang sedang diklaim. Kunci bersama ini membuat penahanan dan penataan ulang tidak bisa saling menembus.FOR UPDATEpada baris pelanggan, sebelum menghitung. Batas 10 kursi per pelanggan per hari adalah hitungan atas baris yang belum ada, jadi tidak ada yang bisa dikunci selain induknya. Mengunci baris pelanggan sendiri menyerialkan penahanan pelanggan itu dan tidak ada yang lain. Tanpa kunci ini, empat penahanan pada empat pertunjukan di hari yang sama lolos semua: 12 kursi terhadap batas 10.
Kunci yang diambil semua orang di awal bukanlah "pengecekan" yang dilarang teknik 1. Kunci menentukan
urutan datangnya transaksi; constraint tetap yang menentukan siapa yang mendapat kursi. Yang dilarang adalah
membaca ketersediaan untuk memutuskan. Satu aturan lagi menyusul dari kisah rantai hash di bawah: ambil
semua kunci baris yang dibutuhkan sebelum penulisan pertama yang ikut mengambil kunci bersama, dan siapkan
percobaan ulang untuk deadlock (40P01).
Teknik 3: transisi status sebagai satu UPDATE bersyarat
UPDATE reservasi SET status = 'confirmed'
WHERE id = $1 AND status = 'held'; -- 0 baris: sudah diubah transaksi lain
UPDATE reservasi SET status = 'cancelled'
WHERE id = $1 AND status IN ('held', 'confirmed');
UPDATE reservasi SET admitted_at = now()
WHERE token_masuk = $1 AND status = 'confirmed'
AND admitted_at IS NULL; -- satu tiket, satu kali masuk
Lost update membutuhkan pembacaan dan penulisan di dua pernyataan. Tulis transisinya sebagai satu
pernyataan bersyarat dan periksa jumlah baris yang berubah: nol berarti transaksi lain menang lebih dulu.
Bila dua transaksi bertabrakan, yang kedua menunggu kunci baris yang pertama, lalu mengevaluasi ulang
WHERE-nya terhadap baris yang baru di-commit. Ia tidak bisa menimpa perubahan yang tidak
dilihatnya. Jangan memeriksa admitted_at lebih dulu dengan SELECT; syarat di
dalam UPDATE itulah pemeriksaannya.
Teknik 4: satu pernyataan, satu snapshot
READ COMMITTED mengambil snapshot baru untuk setiap pernyataan, jadi read skew hanya
mungkin di antara dua pernyataan. Peta kursi aplikasi ini adalah satu kueri SQL, setiap kursi di-left
join ke klaim hidupnya, sehingga sebuah commit terlihat utuh atau tidak sama sekali. Bila sebuah
keputusan bergantung pada beberapa bacaan, kunci yang dibaca (teknik 2). Bila yang dibutuhkan hanya laporan
yang konsisten dari beberapa kueri, jalankan di REPEATABLE READ, yang memakai satu snapshot
untuk seluruh transaksi. Read skew yang tidak memutuskan apa-apa boleh dibiarkan: halaman pesanan membaca
pesanan lalu kursinya dalam dua pernyataan, jadi muat ulang yang jatuh tepat di tengah konfirmasi bisa
menampilkan "menunggu" di atas kursi yang sudah dikonfirmasi, dan tampilan berikutnya benar.
Teknik 5: SERIALIZABLE untuk agregat, dengan satu percobaan ulang
Bila aturannya tentang total atas banyak baris dan tidak ada satu baris pun yang bisa mewakilinya,
misalnya kuota pemesanan aktif seluruh penyewa, jalankan transaksinya di SERIALIZABLE.
PostgreSQL mendeteksi struktur berbahaya di antara transaksi yang berjalan bersamaan dan membatalkan salah
satunya dengan 40001. Ulangi tepat sekali: deteksinya konservatif dan bisa membatalkan pasangan
yang sebenarnya tidak berkonflik. 40001 kedua pada permintaan yang sama berarti persaingannya
nyata; perlakukan seperti 23P01. Bila ada baris induk yang bisa mewakili totalnya, seperti
pelanggan untuk "kursi per hari", FOR UPDATE padanya lebih murah dan bekerja di READ
COMMITTED. Di bawah 18.6, deteksi itu sendiri punya celah (lihat bawah).
Anomali yang tidak disadari: rantai bukti yang bercabang
Log audit platform ini adalah rantai hash per penyewa: setiap baris baru menyimpan hash yang dihitung dari
hash baris sebelumnya, sehingga baris yang diubah belakangan akan ketahuan. Fungsi trigger-nya mencari baris
terakhir penyewa dengan SELECT row_hash … ORDER BY audit_id DESC LIMIT 1, tanpa kunci. Di
READ COMMITTED, baris yang belum di-commit tidak terlihat, jadi dua transaksi penyewa yang sama
yang menulis bersamaan sama-sama menautkan diri ke baris pendahulu yang sama. Rantainya bercabang, dan
pemeriksaan rantai melaporkan baris kedua sebagai hasil pemalsuan, padahal tidak ada yang menyentuhnya.
Ini pola phantom yang sama dengan "cek dulu, lalu simpan": membaca "baris terakhir" lalu menambahkan sesudahnya. Cacat seperti ini bisa bertahan lama tanpa ketahuan, karena tidak ada kode yang memverifikasi rantainya. Ketika ditemukan pada 25 September 2026 oleh pengujian yang sengaja menahan satu tulisan tetap terbuka, 34 baris log di server yang hidup masih utuh hanya karena lalu lintas demo tidak pernah bertabrakan. Begitu lalu lintas sungguhan bertabrakan, setiap cabang akan permanen, karena log audit hanya bisa ditambah, dan memperbaiki baris lama adalah pemalsuan itu sendiri. Seandainya dibiarkan, hari ketika seseorang memeriksa log itu sebagai bukti, ia akan gagal pada lalu lintas biasa.
Perbaikannya, 15 Oktober 2026, adalah kunci advisory per penyewa yang diambil sebelum pembacaan:
-- di dalam fungsi trigger, sebelum mencari baris terakhir penyewa
PERFORM pg_advisory_xact_lock(hashtext('audit_log'), hashtext(NEW.tenant_id::text));
SELECT row_hash INTO prior_hash FROM audit_log
WHERE tenant_id = NEW.tenant_id ORDER BY audit_id DESC LIMIT 1;
Penulis kedua menunggu sampai penulis pertama commit, lalu membaca barisnya. Alternatifnya, mencatat ID baris pendahulu di setiap baris, ditolak: cabangnya tetap ada, dan saudara yang kalah menjadi daun yang tidak ditautkan siapa pun, yang bisa dihapus tanpa jejak. Harganya, tulisan teraudit satu penyewa bergiliran dari baris audit pertamanya sampai commit, dan itulah asal aturan urutan kunci di teknik 2.
Membuktikan: cabut pelindungnya, lihat anomalinya muncul
Uji konkurensi yang lulus belum membuktikan apa-apa. Jalankan setiap uji dua kali: sekali terhadap kode
sebenarnya, sekali terhadap versi yang sengaja dilemahkan. Bila versi lemah tidak menghasilkan anomalinya,
ujinya tidak menguji apa yang Anda kira. Karena tidak ada tingkat isolasi di bawah READ
COMMITTED untuk dituju, yang dilemahkan adalah pelindung desainnya:
- Constraint eksklusi dicabut dari skema hasil migrasi sungguhan: kedelapan penahanan serentak pada satu kursi berhasil.
- Kunci baris pelanggan dihapus: empat penahanan lolos hitungan, 12 kursi terhadap batas 10.
FOR UPDATEpada pertunjukan digantiSELECTbiasa: muncul tahanan untuk pertunjukan yang sudah dibatalkan.
Sisipkan jeda buatan di antara pemeriksaan dan penulisan lewat properti yang hanya aktif di profil uji, supaya dua permintaan pasti jatuh di jendela balapannya alih-alih berharap kebetulan. Semua ini hanya bisa diuji terhadap PostgreSQL sungguhan: proyek ini menjalankan setiap kueri terhadap PostgreSQL 18.6 yang sudah dimigrasi lewat Testcontainers di setiap build, dengan versi image uji yang mengikuti server yang hidup. Pengujian terhadap aplikasi yang hidup tetap berguna untuk menunjukkan perilakunya di jaringan dan konfigurasi sungguhan, tetapi ia hanya menunjukkan ketiadaan anomali pada percobaan yang dilakukan. Yang membuat anomalinya mustahil adalah mekanismenya.
Yang khusus di PostgreSQL 18.6
PostgreSQL 18.6 dirilis 13 Agustus 2026 dan memuat perbaikan sejak 18.4. Tiga di antaranya menyentuh langsung teknik di atas:
- Deteksi konflik
SERIALIZABLE. Sebuah konflik bisa terlewat saat memeriksa indeks btree yang awalnya kosong, sehingga transaksi yang saling bertentangan diizinkan commit. Bila Anda mengandalkan teknik 5, versi minimalnya 18.6. - Index-only scan GiST. Tuple indeks bisa salah didekode dan rencana
index-only scan mengeluarkan data rusak. Satu-satunya kelas operator inti yang terdampak adalah
range_opsGiST, dan hanya bila kolom rentangnya bukan kolom pertama indeks. Itulah persis bentukEXCLUDE USING gist (kursi WITH =, periode WITH &&). - Operator tidak-sama di
btree_gist. Untuk tipe panjang-variabel sepertitext, pencarian dengan<>memakai fungsi pembanding yang salah di halaman non-daun, dengan hasil salah dan kemungkinan crash. Ini relevan bagi constraint eksklusi yang memakaiWITH <>, misalnya "satu kandang hanya untuk satu jenis hewan".
Catatan migrasinya juga meminta pembangunan ulang beberapa indeks setelah memasang 18.6: indeks
btree_gist pada kolom float4 atau float8 bila kolomnya mungkin berisi
NaN (perbandingannya salah), indeks btree_gist pada kolom bit atau
varbit (indeksnya tidak efisien), dan indeks btree atas nilai ltree dengan lebih
dari sekitar 14.653 label (perbandingannya meluap). Indeks yang menjawab salah tidak tampak rusak, dan bagi
constraint eksklusi jawaban yang salah berarti pemesanan ganda atau kursi kosong yang ditolak. Tanyakan ke katalog, bukan ke skema yang Anda
ingat. Kueri ini menemukan setiap indeks atas tipe-tipe itu, termasuk indeks atas ekspresi, karena ia lewat
kelas operatornya:
SELECT n.nspname AS skema, c.relname AS tabel, i.relname AS indeks, am.amname AS metode,
pg_get_indexdef(i.oid) AS definisi
FROM pg_index x
JOIN pg_class i ON i.oid = x.indexrelid
JOIN pg_class c ON c.oid = x.indrelid
JOIN pg_am am ON am.oid = i.relam
JOIN pg_namespace n ON n.oid = i.relnamespace
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
AND EXISTS (SELECT 1
FROM unnest(x.indclass::oid[]) AS cls(oid)
JOIN pg_opclass o ON o.oid = cls.oid
JOIN pg_type t ON t.oid = o.opcintype
WHERE t.typname IN ('ltree', 'bit', 'varbit', 'float4', 'float8'))
ORDER BY 1, 2, 3;
-- untuk setiap baris hasilnya, di server yang sedang melayani:
REINDEX INDEX CONCURRENTLY nama_skema.nama_indeks; -- tidak bisa di dalam blok transaksi
-- SQL ekstensi bisa tertinggal dari binarinya setelah naik versi
SELECT name, default_version, installed_version FROM pg_available_extensions
WHERE name IN ('btree_gist', 'pgcrypto'); -- bila tertinggal: ALTER EXTENSION btree_gist UPDATE;
Di platform ini kueri itu mengembalikan nol baris pada 22 Agustus 2026. Satu-satunya indeks GiST-nya
adalah constraint eksklusi atas uuid dan tstzrange, dan dua tempat yang wajar untuk
bilangan titik mengambang sengaja memakai numeric: uang numeric(14,2), dan lintang
serta bujur cabang numeric(9,6). Keputusan menghindari float itu ternyata membayar
dividen yang tidak diduga siapa pun.
PostgreSQL 18: WITHOUT OVERLAPS
Sejak PostgreSQL 18, yang dirilis 25 September 2025, kunci primer dan constraint unik dapat ditulis dengan
WITHOUT OVERLAPS pada kolom terakhirnya, dan kunci asing dapat memakai PERIOD.
Dokumentasinya menyebut constraint semacam itu ditegakkan sebagai exclusion constraint dengan indeks GiST:
UNIQUE (id, valid_at WITHOUT OVERLAPS) berperilaku seperti EXCLUDE USING GIST (id WITH =,
valid_at WITH &&). Kolom rentangnya tidak boleh kosong, dan kolom skalar di sebelahnya
membutuhkan btree_gist. Untuk data master yang tidak boleh tumpang tindih, seperti periode
harga, tarif, atau masa jabatan, bentuk ini lebih ringkas:
CREATE TABLE harga_produk (
produk_id bigint NOT NULL,
berlaku daterange NOT NULL,
harga_rupiah numeric(14,2) NOT NULL,
PRIMARY KEY (produk_id, berlaku WITHOUT OVERLAPS)
);
Namun constraint unik tidak bisa diberi klausa WHERE. Untuk pemesanan, yang hanya melarang
tumpang tindih di antara baris yang masih held atau confirmed, EXCLUDE …
WHERE tetap alat yang tepat.
5. Di luar bioskop: siapa lagi yang diuntungkan?
Catatan desain platform bioskop ini merumuskannya begini: kursi bioskop untuk satu pertunjukan dan
kamar hotel untuk satu rentang tanggal adalah masalah yang sama bila dinyatakan dengan tepat.
Keduanya klaim eksklusif atas satu sumber daya, untuk satu periode, di mana dua klaim yang
tumpang tindih tidak boleh sama-sama berlaku. Setiap domain yang cocok dengan kalimat itu bisa
memakai pola yang sama: kolom sumber daya dengan = dan kolom rentang dengan
&&. Skema platform ini sengaja dibuat generik untuk itu: tabel yang sama memetakan
aula ke properti, kursi ke kamar, dan periode pertunjukan ke [check-in, check-out).
| Domain | Sumber daya (WITH =) |
Rentang (WITH &&) | Catatan |
|---|---|---|---|
| Hotel, vila, homestay | kamar | daterange [check-in, check-out) |
Hari check-out sudah bebas untuk tamu berikutnya karena batas atasnya terbuka. |
| Ruang rapat, coworking, aula, gedung resepsi | ruangan, meja | tstzrange |
Waktu persiapan dan bersih-bersih ikut dimasukkan ke rentang yang disimpan. |
| Lapangan futsal, badminton, padel | lapangan | tstzrange per jam |
Pemesanan beruntun 19.00–20.00 dan 20.00–21.00 sah bersama. |
| Klinik dan rumah sakit | dokter; ruang praktik; kamar operasi; tempat tidur; alat MRI | tstzrange |
Satu tabel janji temu boleh memuat dua constraint: dokter tidak ganda dan ruangan tidak ganda. |
| Kereta dan bus antarkota | kursi pada satu perjalanan | int4range urutan stasiun [naik, turun) |
Kursi yang sama bisa dijual untuk segmen yang tidak beririsan, misalnya stasiun 1–4 lalu 4–7. |
| Sewa mobil, motor, kamera, alat berat | unit (nomor polisi, nomor seri) | tstzrange |
Cocok untuk unit yang dapat dibedakan, bukan "mobil kelas apa saja". |
| Pelabuhan dan bandara | dermaga; gerbang | tstzrange |
Slot sandar kapal dan slot gerbang pesawat adalah klaim eksklusif berwaktu. |
| Gudang dan logistik | pintu bongkar muat | tstzrange |
Jadwal kedatangan truk tanpa dua truk di satu pintu pada waktu yang sama. |
| Sekolah, kampus, ujian | ruang kelas; laboratorium; kursi ujian; pengawas | tstzrange |
Satu pengawas tidak bisa dijadwalkan di dua ruang sekaligus. |
| Sumber daya manusia | karyawan | tstzrange shift |
Satu orang tidak bisa memegang dua shift yang beririsan. Bila shift dan cuti juga tidak boleh bertabrakan, simpan keduanya di satu tabel jadwal. |
| Penyiaran dan iklan | kanal; papan reklame digital | tstzrange slot tayang |
Dua materi tidak boleh menempati slot yang sama. |
| Data master bertanggal | produk; kode pajak; pasangan mata uang; jabatan | daterange masa berlaku |
Tidak boleh ada dua harga atau dua tarif yang berlaku bersamaan untuk hal yang sama. Di
PostgreSQL 18, WITHOUT OVERLAPS. |
| Asuransi dan perjanjian | aset; nomor polis atau perjanjian | daterange masa pertanggungan |
Dua polis aktif atas aset yang sama tidak boleh tumpang tindih, bila produknya melarangnya. |
| Jaringan dan spektrum | switch; antarmuka; wilayah | int4range VLAN atau port; numrange pita frekuensi |
Untuk blok alamat IP, tipe inet dengan kelas operator GiST inet_ops
memakai operator && yang sama. |
Contoh: kursi kereta per segmen
CREATE TABLE klaim_kursi (
perjalanan_id bigint NOT NULL,
kursi text NOT NULL,
segmen int4range NOT NULL, -- [urutan stasiun naik, urutan stasiun turun)
status text NOT NULL,
EXCLUDE USING gist (perjalanan_id WITH =, kursi WITH =, segmen WITH &&)
WHERE (status IN ('held', 'confirmed'))
);
-- [1,4) dan [4,7) sah bersama: penumpang pertama turun di stasiun ke-4, yang kedua naik di sana.
-- [1,4) dan [3,6) ditolak dengan 23P01.
Contoh: satu janji temu, dua larangan
CREATE TABLE janji_temu (
dokter_id bigint NOT NULL,
ruang_id bigint NOT NULL,
waktu tstzrange NOT NULL,
status text NOT NULL,
EXCLUDE USING gist (dokter_id WITH =, waktu WITH &&) WHERE (status <> 'batal'),
EXCLUDE USING gist (ruang_id WITH =, waktu WITH &&) WHERE (status <> 'batal')
);
Kapan pola ini bukan alat yang tepat
- Kapasitas yang dapat dipertukarkan. Constraint ini melindungi klaim atas unit
tertentu. Tiket festival tanpa nomor kursi, "kamar deluxe mana saja", atau kuota 100 peserta
adalah masalah menghitung, bukan tumpang tindih. Hitunglah di dalam transaksi setelah mengunci baris yang
menjadi lingkup hitungan (teknik 2 di bagian 4), atau pakai
SERIALIZABLEdengan satu kali percobaan ulang untuk40001(teknik 5). Hotel umumnya menjual tipe kamar lebih dulu, yang merupakan soal kapasitas, lalu menetapkan nomor kamar kemudian, yang merupakan soal eksklusi. - Aturan yang bergantung pada waktu sekarang, seperti "tahanan berlaku 10 menit". Predikat harus immutable, jadi simpan statusnya dan kedaluwarsakan dengan penyapu.
- Bentuk geometri yang presisi. Di PostGIS,
&&padageometryhanya membandingkan kotak pembatas (bounding box). Dua bidang yang tidak bersentuhan pun bisa ditolak bila kotaknya beririsan, jadi larangan tumpang tindih yang presisi butuh cara lain. - Kepemilikan yang tersebar di beberapa basis data atau layanan. Constraint hanya berlaku di dalam satu basis data. Data yang dipecah (sharding), atau sistem kedua yang ikut menjual unit yang sama, menghapus jaminan ini.
- Basis data yang tidak memilikinya. Sebelum memilih basis data, termasuk layanan
PostgreSQL terkelola, periksa apakah ia sendiri bisa menegakkan aturan "tidak boleh tumpang tindih" dan
mengizinkan ekstensi
btree_gist. Bila tidak, jaminan itu harus dibangun ulang di aplikasi, tempat anomali di atas paling mudah lolos.
6. Pertanyaan yang sering diajukan
Apakah agen elektronik dalam UETA 1999 berarti agen AI?
Tidak. Komentar resmi UETA menyebut agen elektronik sebagai mesin yang terbatas pada fungsi alat dan bekerja di dalam batasan pemrogramannya. Agen yang bertindak otonom, bukan sekadar otomatis, baru diantisipasi sebagai kemungkinan di masa depan, dan penafsirannya diserahkan kepada pengadilan.
Apakah server web yang menerima pesanan termasuk agen elektronik?
Ya. Contoh dari perancang UETA sendiri adalah Bookseller.com, yang menerima dan mengonfirmasi pesanan lewat mesinnya. Aplikasi yang menahan kursi, menerima pembayaran, dan menerbitkan tiket tanpa ditinjau manusia adalah agen elektronik milik penjualnya, termasuk basis data di dalamnya, walaupun keputusan menerima atau menolak klaim kursi diambil oleh constraint di PostgreSQL.
Di Indonesia, siapa yang menanggung akibat hukum transaksi lewat agen elektronik?
Menurut UU ITE Pasal 21 ayat (2) huruf c, penyelenggara Agen Elektronik. Kerugian karena agen gagal beroperasi akibat tindakan pihak ketiga juga ditanggung penyelenggara (ayat 3), kerugian karena kelalaian pengguna jasa ditanggung pengguna (ayat 4), dan tanggung jawab penyelenggara tidak berlaku bila dapat dibuktikan keadaan memaksa, kesalahan, atau kelalaian pengguna (ayat 5).
Fitur apa yang wajib disediakan penyelenggara agen elektronik?
PP 71/2019 Pasal 37 ayat (3) menyebut fasilitas untuk melakukan koreksi, membatalkan perintah, memberikan konfirmasi atau rekonfirmasi, memilih meneruskan atau berhenti, melihat informasi tawaran, mengecek status berhasil atau gagalnya transaksi, dan membaca perjanjian sebelum bertransaksi, sesuai karakteristik agennya. Ayat (1) mewajibkan informasi seperti identitas penyelenggara, syarat perjanjian, jaminan privasi, dan nomor telepon pengaduan. Pelanggarannya dikenai sanksi administratif menurut Pasal 100.
Bolehkah agen AI langsung memesan atas nama pelanggan?
Sebaiknya tidak. UETA Pasal 10 ayat 2 membolehkan individu menghindari akibat kesalahannya bila agen elektronik pihak lain tidak memberi kesempatan untuk mencegah atau mengoreksinya, dan PP 71/2019 mewajibkan fitur koreksi dan konfirmasi. Biarkan agen mengusulkan, misalnya lewat peta kursi yang pilihannya sudah tercentang, dan biarkan pelanggan sendiri yang menekan tombol tahan dan bayar.
Apa itu anomali Adya?
Taksonomi anomali isolasi dari tesis Atul Adya di MIT (1999) dan makalah ICDE 2000 yang ia tulis bersama Barbara Liskov dan Patrick O'Neil. Setiap anomali didefinisikan sebagai siklus tertentu pada graf ketergantungan antartransaksi yang sudah di-commit, atau sebagai pembacaan data yang seharusnya tidak terlihat: G0 (siklus tulis), G1a, G1b, dan G1c (bacaan kotor), G-cursor (lost update), G-single (read skew), G2-item (write skew), dan G2 (phantom). Karena tidak bergantung pada penguncian, definisi itu cocok untuk basis data multiversi seperti PostgreSQL.
Mengapa tidak cukup mengecek apakah kursi masih kosong, lalu menyimpan?
Karena dua transaksi bersamaan sama-sama melihat kursi kosong dan sama-sama menyimpan.
READ COMMITTED dan REPEATABLE READ membiarkannya; ini write skew.
Constraint eksklusi menolak klaim kedua saat ditulis, pada tingkat isolasi apa pun, dengan SQLSTATE
23P01.
Tingkat isolasi PostgreSQL mana yang mencegah anomali apa?
READ COMMITTED, bawaan PostgreSQL, mencegah G0, G1a, G1b, dan G1c. REPEATABLE
READ, yang di PostgreSQL berupa snapshot isolation, menambahkan lost update dan read skew.
Hanya SERIALIZABLE yang juga mencegah write skew dan phantom, dengan membatalkan salah satu
transaksi lewat SQLSTATE 40001. READ UNCOMMITTED diterima tetapi berperilaku seperti
READ COMMITTED.
Apa yang perlu diperhatikan saat memakai PostgreSQL 18.6?
Versi 18.6, dirilis 13 Agustus 2026, memperbaiki deteksi konflik SERIALIZABLE yang bisa
melewatkan konflik pada indeks btree yang awalnya kosong, index-only scan GiST atas kolom rentang
yang bukan kolom pertama indeks, dan pencarian btree_gist dengan operator tidak-sama. Setelah
naik versi, bangun ulang indeks btree_gist pada kolom float yang mungkin berisi
NaN, indeks btree_gist pada kolom bit, dan indeks btree atas ltree.
Apa bedanya WITHOUT OVERLAPS di PostgreSQL 18 dengan EXCLUDE?
WITHOUT OVERLAPS adalah bentuk standar untuk kunci primer dan constraint unik atas rentang,
dan ditegakkan sebagai exclusion constraint GiST. Cocok untuk data master seperti periode harga. Constraint
unik tidak bisa diberi klausa WHERE, jadi untuk pemesanan yang hanya melarang tumpang tindih di
antara baris yang masih aktif, EXCLUDE dengan WHERE tetap dibutuhkan.
Domain apa saja selain bioskop yang cocok memakai constraint eksklusi?
Semua yang berbentuk klaim eksklusif atas satu sumber daya untuk satu periode: hotel, ruang rapat, lapangan olahraga, jadwal dokter dan kamar operasi, kursi kereta per segmen, sewa kendaraan dan alat, dermaga, shift karyawan, periode harga dan tarif, polis asuransi, serta rentang VLAN atau frekuensi. Untuk kapasitas yang dapat dipertukarkan, seperti tiket tanpa nomor kursi, gunakan penghitungan dengan penguncian baris.
7. Sumber
- National Conference of Commissioners on Uniform State Laws, Uniform Electronic Transactions Act (1999), with Prefatory Note and Comments: Pasal 2 angka 2 dan 6 beserta komentarnya, Pasal 10, dan Pasal 14.
- D. Greenwood dan J. Muller, memo kelompok kerja ABA untuk komite perancang UETA, 16 Februari 1999, dimuat ulang di MIT Computational Law Report.
- Undang-Undang Nomor 11 Tahun 2008 tentang Informasi dan Transaksi Elektronik, JDIH Kementerian Keuangan: Pasal 1 angka 8, Pasal 6, Pasal 21, dan Pasal 22.
- Peraturan Pemerintah Nomor 71 Tahun 2019 tentang Penyelenggaraan Sistem dan Transaksi Elektronik, JDIH BPK: Pasal 1 angka 3, Pasal 36 sampai 39, dan Pasal 100.
- Undang-Undang Nomor 27 Tahun 2022 tentang Pelindungan Data Pribadi, JDIH BPK: Pasal 56.
- A. Adya, Weak Consistency: A Generalized Theory and Optimistic Implementations for Distributed Transactions, tesis PhD, MIT, 1999; dan A. Adya, B. Liskov, dan P. O'Neil, Generalized Isolation Level Definitions, ICDE 2000, hlm. 67–78.
- PostgreSQL 18: Transaction
Isolation, Explicit
Locking, CREATE
TABLE (
EXCLUDEdanWITHOUT OVERLAPS), Range Types, btree_gist, catatan rilis PostgreSQL 18, dan catatan rilis PostgreSQL 18.6. - Loop agen, dokumentasi resmi: Quarkus LangChain4j, Koog, LangGraph, Google ADK, Claude Agent SDK dan Claude Code: Other LLM gateways, Microsoft Agent Framework, OpenAI Agents SDK, serta Amazon Bedrock AgentCore (gambaran umum dan Harness).
- Model dan platform: Amazon Bedrock model support by AWS Region dan API compatibility, Amazon Nova sebagai model dasar agen, Anthropic OpenAI SDK compatibility, README Jython (status Python 2.7 dan Jython 3), serta halaman model, data residency, dan penyedia dalam negeri yang ditautkan di bagian 2. Data region per 15 Oktober 2026, data tabel loop per 13 Oktober 2026.
- Kode sumber platform pemesanan kursi bioskop yang menjadi dasar halaman ini, dawud-tan/movie-ticket (Apache-2.0), beserta catatan desain, catatan biaya, hasil pengukuran, dan riwayat perbaikannya yang tidak ikut dipublikasikan. Percobaan anomalinya terhadap deployment Anda sendiri dibahas di halaman Adya's Isolation Anomalies.
Harga, ketersediaan layanan, region, dan angka tolok ukur berubah dari waktu ke waktu. Periksa sumber resminya sebelum mengambil keputusan.