AIDive

4 Gerbang Shopify di Claude Code: Cuma Tes yang Ampuh

Oleh AIDive · Terbit

Coding agentOtomatisasi & workflow

Intro: gerbang yang menolak kata selesai

Gerbang, dalam arti yang dipakai Shopify, adalah pemeriksaan yang harus dilewati sebuah perubahan buatan AI sebelum boleh lanjut. Setelah dibangun ulang di Claude Code, hanya gerbang pertama yang terbukti berguna: tes penerimaan. Shopify memublikasikan empat gerbang tanpa satu pun angka, jadi eksperimen ini membangunnya di repositori nyata, menjalankan lima puluh permintaan dengan tiap gerbang dimatikan bergantian, lalu menghitung apa yang berhasil ditangkap masing-masing dan berapa biayanya.

Helix dirilis ke publik pada 21 September 2026. Alat ini melewatkan setiap checkpoint melalui empat gerbang secara berurutan: tes, review desain, dua reviewer, dan seorang engineer. Postingannya tidak menyebut pass rate. Para reviewer adalah bagian yang paling banyak ditiru, dan pada lima puluh run ini pass rate hanya bergerak ketika tes ikut dalam loop. Para reviewer tidak menambah apa-apa, dengan biaya kira-kira tiga kali lipat.

Dua temuan lain muncul dari bench yang sama. Sebuah hook yang katanya tidak bisa ditimpa ternyata punya tiga jalan keluar di dokumentasinya sendiri. Dan ketika tes dan reviewer tidak sepakat, agent melakukan sesuatu yang tidak direncanakan siapa pun. Penghitungan dimulai dari kasus tanpa gerbang sama sekali.

Empat gerbang, nol angka, satu bench

Repositori bench-nya adalah tinydb, database dokumen nyata, dengan 226 tes hijau pada commit yang dipakai.

Helix adalah alat internal Shopify untuk memindahkan aplikasi mobile mereka kembali ke kode native. Postingannya menyatakan aturannya dengan lugas: setiap checkpoint melewati empat gerbang, secara berurutan.

Gerbang Apa yang dilakukannya menurut postingan Shopify
Behaviour Menjalankan tes yang setiap kasus relevannya harus lulus
Design Meminta model kedua berperan sebagai reviewer desain yang perfeksionis
Review Dua agent reviewer independen dengan konteks terisolasi; loop diulang sampai keduanya menyetujui
Engineer Seorang manusia menutup loop

Kalimat yang menjual desain ini adalah "An attempt is allowed to be wrong. It is not allowed to ship until it isn't." Gerbang desain gugur untuk sebuah library, dan postingan itu menyebut perubahan yang hanya menyangkut logika memang melewatinya.

Yang tidak pernah diberikan postingan itu adalah angka. Aplikasi Shop dibangun ulang dalam 12 minggu dan aplikasi Shopify punya lebih dari 300 layar, dan hanya itulah seluruh catatannya. Tidak ada pass rate, tidak ada biaya, dan tidak ada hitungan cacat yang lolos.

Bench-nya terdiri dari lima permintaan yang diketik seperti developer mengetik: operasi push dan pull, query between, penggantian nama tabel, pencarian terurut, dan ukuran write cache. Di balik tiap permintaan ada lima syarat tersembunyi yang tidak pernah dilihat agent, hal-hal yang diharapkan seorang senior engineer yang teliti. Totalnya 25 syarat.

Worker-nya adalah Sonnet 5.5, dijalankan headless. Lima konfigurasi kali lima tugas kali dua pengulangan menghasilkan 50 run. Satu catatan berlaku: versi eksplisit dari permintaan ini lulus dalam sekali jalan, jadi prompt dipersingkat menjadi apa yang benar-benar diketik orang.

Tanpa gerbang sama sekali, 35 dari 50 syarat lulus. Itu 70%, dengan tiga run dari sepuluh yang bersih sepenuhnya.

Tugas sort menunjukkan seperti apa kegagalannya. Agent mengindeks setiap dokumen dengan field pengurutan, dan begitu satu dokumen tidak memiliki field itu, seluruh pencarian crash. Lima syarat, nol lulus, satu key yang hilang.

Hook yang menolak selesai, dan tiga jalan keluarnya

Stop hook adalah skrip yang dijalankan Claude Code setiap kali agent mencoba mengakhiri gilirannya. Panduan resmi Anthropic menyebut masalah yang ditanganinya: Claude berhenti ketika pekerjaan tampak selesai. Tanpa pemeriksaan yang bisa dijalankan, "tampak selesai" adalah satu-satunya sinyal yang tersedia, dan kamu sendiri yang menjadi loop verifikasinya.

Hook ini berada di file settings proyek, di bawah hooks, Stop, sebagai satu command dengan timeout. Di sini bentuknya wrapper satu baris yang memanggil skrip gerbang. Kontraknya adalah exit code: 0 membiarkan giliran berakhir, 2 memblokirnya, dan apa pun yang dicetak skrip ke standard error dikirim kembali ke agent sebagai alasannya.

Dalam praktik, jalannya begini. Agent merangkum perubahannya lalu berhenti. Hook menjalankan tes penerimaan, satu tes gagal, dan giliran tidak berakhir. Agent membaca kegagalan itu sebagai feedback dari hook, dalam kasus ini sebuah tes yang mengharapkan type error dan tidak mendapatkannya, memperbaiki kodenya, lalu berhenti lagi. Kali ini gerbangnya diam.

Aturan di dalam prompt hanyalah saran. Hook bukan saran. Namun halaman dokumentasi yang sama mencantumkan tiga jalan keluar.

Jalan keluar Apa kata dokumentasi
Batas (cap) Setelah stop hook melanjutkan giliran 8 kali berturut-turut, Claude Code menimpa blokir berikutnya dan mengakhiri giliran. Hitungan di-reset setiap kali agent memanggil tool, dan sebuah environment variable bisa menaikkannya.
Timeout Default 600 detik untuk command hook, dan hook yang kena timeout tidak menghasilkan keputusan. Test suite yang lambat membuka gerbang dengan sendirinya.
Flag Input hook membawa stop_hook_active, bernilai true ketika sesi sedang berlanjut karena sebuah stop hook. Dokumen menyuruh memeriksanya agar kamu tidak pernah memblokir karena kondisi yang tidak bisa terselesaikan.

Gerbang di sini mencatat flag itu dan mengabaikannya. Ia menyerah sendiri setelah enam blokir, sehingga loop tetap bisa dihitung.

Ada satu jalan keluar lagi yang tidak didokumentasikan siapa pun. Setelah diblokir sekali, agent mencari tesnya: ia menjalankan cat pada skrip hook dan menyisir seluruh disk untuk menemukan file tes. Hanya allow list yang menghentikannya. Karena itu tes penerimaan disimpan di luar pohon repositori, settings menolak pembacaan hook dan tes tersembunyi, dan agent melihat kegagalannya tetapi tidak pernah melihat file-nya.

Gerbang 1: tes penerimaan

Gerbang tes penerimaan adalah sekumpulan tes, ditulis terpisah dari implementer, yang mendefinisikan arti "selesai". Gerbang pertama Shopify bukan tes milik agent sendiri. Sebuah subagent menghasilkan test case bergaya integrasi untuk setiap checkpoint, mendorong edge case di luar happy path, dan tes-tes itulah yang mendefinisikan arti terbukti.

Karena itu writer di sini adalah Sonnet headless terpisah. Ia melihat permintaan dan repositori sebelum perubahan, hanya-baca, tidak bisa menjalankan kode, dan diminta menulis satu tes untuk setiap perilaku yang diharapkan seorang senior yang teliti: field yang hilang, tipe yang salah, batas nilai, persistensi, cache, dan perilaku lama yang tidak berubah. Ia menulis antara 23 dan 53 tes, rata-rata 39, dalam sekitar 40 detik. File-nya mendarat di luar repositori, sehingga ketika sebuah tes gagal, agent membaca assertion-nya dan tidak pernah membaca tesnya.

Tes saja sudah menaikkan pass rate dari 70% ke 84%: 42 dari 50 syarat, dan enam run bersih sepenuhnya, bukan tiga.

Tugas Tanpa tes Dengan tes
Pencarian terurut 5 dari 10 10 dari 10
Ukuran write cache 8 dari 10 10 dari 10
Push dan pull 4 dari 10 4 dari 10

Crash field yang hilang pada tugas sort persis jenis kasus yang ditanyakan writer. Untuk tugas cache, writer menuntut value error untuk ukuran cache di bawah satu.

Tugas push dan pull tidak bergerak. Tiga syaratnya meleset, dua di antaranya soal dokumen tanpa field itu, dan permintaannya tidak pernah menyinggungnya. Writer berspekulasi persis di tempat prompt diam: tesnya menerima raise atau no-op diam-diam, sehingga gerbang tidak bisa memulihkan syarat yang tidak pernah dinyatakan siapa pun.

Dari 30 run bergerbang dengan tes, gerbang mengirim agent kembali 28 kali dengan syarat nyata yang gagal, dan lima kali ketika semuanya lulus. Salah satu dari lima itu adalah tugas rename: writer menginginkan nama yang bukan string ditolak, tidak ada yang memintanya, dan agent kehilangan satu ronde karenanya.

Versi pertama gerbang ini menjalankan ulang tes milik implementer sendiri. Ia mengizinkan setiap run pada stop pertamanya padahal sebuah syarat tersembunyi gagal, karena tes milik agent menguji apa yang ia bangun.

Harga gerbang ini $0.20 per run, bukan $0.085, dan 60 detik, bukan 33.

Gerbang 3: dua reviewer, seperti tulisan Shopify

Gerbang review adalah sepasang agent reviewer, masing-masing bekerja di konteks baru. Kata-kata Shopify: dua agent reviewer independen dengan konteks terisolasi memeriksa kode baru, setiap temuan harus diperbaiki, dan loop diulang sampai kedua reviewer menyetujui. Panduan Anthropic menjelaskan mengapa isolasi penting: reviewer di konteks baru hanya melihat diff dan kriteria yang kamu berikan, bukan penalaran yang menghasilkan perubahan itu.

Setiap reviewer di sini adalah Sonnet headless dengan tool hanya-baca dan paling banyak 15 giliran. Ia mengembalikan vonis sebagai JSON terstruktur: flag approve dan temuan, masing-masing dengan severity blocking atau minor. Dua reviewer berjalan paralel pada permintaan dan diff lengkap, temuan mereka digabung, dan gerbang memblokir ketika salah satunya menemukan sesuatu yang blocking. Sepasang reviewer berbiaya antara 3 dan 6 sen per stop.

Konfigurasi Syarat lulus Pass rate Blokir
Tanpa gerbang 35 dari 50 70% tidak ada
Reviewer saja 34 dari 50 68% 1 dari 10 run
Tes saja 42 dari 50 84% 6 dari 10 run (3 tepat, 3 salah)
Reviewer setelah tes 41 dari 50 82% 2 dari 10 run, keduanya tepat

Reviewer saja berada dua poin di bawah tanpa gerbang sama sekali, dan reviewer setelah tes berada dua poin di bawah tes saja.

Tugas sort menjelaskan angkanya. Dalam satu run kedua reviewer memblokir: pengurutan mengindeks dokumen, satu dokumen tanpa field itu memunculkan key error, dan seluruh pencarian gagal. Agent memperbaikinya dan lulus lima dari lima.

Di dua run lain kedua reviewer melihat crash yang persis sama dan menilainya minor. Dokumen tanpa field pengurutan memunculkan key error polos, dan docstring-nya mendokumentasikan hal itu. Kedua reviewer menyetujui, dan kedua run berakhir di nol dari lima. Model sama, diff sama, bug sama, dua severity berbeda. Para reviewer tidak pernah salah ketika memblokir. Masalahnya ada pada apa yang mereka loloskan.

Sebuah paper bulan Agustus mengukur pola yang sama pada benchmark publik. Zero-shot mencetak 77%, satu reviewer 77%, dan dua reviewer independen 75%, semuanya dalam noise dibanding tanpa review sama sekali.

Setup di LiveCodeBench Skor
Zero-shot 77%
Satu reviewer 77%
Dua reviewer independen 75%
Reviewer plus critic (adversarial review) 87%

Reviewer plus critic, dan loop yang tak pernah berakhir

Adversarial review adalah reviewer yang dipasangkan dengan critic yang mengaudit review itu lewat ketidaksepakatan terstruktur sebelum agent utama mengedit. Paper yang sama menemukan bahwa inilah bentuk yang berhasil. Skornya 87% di mana dua reviewer mendapat 75%, dan mengalahkan baseline lima agent terkuat di angka 82%.

Benchmark Zero-shot Dengan adversarial review Biaya
SWE-bench 71.6 75.2 sekitar 4.5x token

Maka critic dimasukkan ke dalam gerbang. Reviewer A mereview. Critic B menerima temuan beserta diff dan menandai tiap temuan sebagai upheld atau rejected. Hanya temuan blocking yang upheld yang menutup gerbang.

Pada repositori ini hasilnya 39 dari 50, atau 78%. Pasangan critic memblokir nol kali dalam sepuluh run. Saat validasi, ia memang menolak satu temuan palsu yang akan diblokir oleh bentuk dua reviewer.

Yang tidak bisa diperbaiki critic adalah loop-nya. Tiga run mencapai enam blokir pada tes penerimaan yang sama, dan gerbang menyerah dengan syarat nyata yang masih gagal di setiap stop. Pada dua di antaranya tes yang memblokir adalah kesalahan writer sendiri, dan agent mengatakannya: ia tidak akan mengubah kode demi tes yang tidak bisa ia baca.

Yang ketiga adalah yang paling perlu diingat. Tes penerimaan menginginkan update yang gagal tidak menyentuh dokumen mana pun, jadi agent menulis ulang method update milik tabel. Para reviewer memblokirnya, karena perubahan pada method update tidak diminta dan tugasnya hanya dua fungsi baru. Agent mengembalikannya. Pesan terakhirnya mengatakan bahwa tes penerimaan dan code review meminta hal yang berlawanan, sehingga ia berhenti tanpa mengubah apa pun. Enam blokir kemudian, counter melepaskannya.

Titik menyerah di sini ada di enam. Cap milik Claude Code sendiri adalah delapan blokir berturut-turut dan di-reset pada setiap pemanggilan tool, sehingga ia tidak pernah menyala sekali pun dalam lima puluh run.

Gerbang 4 adalah kamu: apa yang sampai ke manusia, biayanya, kit-nya

Gerbang keempat adalah engineer, dan postingan Shopify menjanjikan bahwa gerbang tidak menjadi lebih longgar ketika tidak ada yang mengawasi. Yang sampai ke engineer adalah apa pun yang diloloskan gerbang lainnya. Ledger di bawah ini menjawab gerbang mana yang sepadan dengan harganya.

Konfigurasi Lulus dari 50 Pass rate Biaya per run Tersisa untuk manusia
Tanpa gerbang 35 70% $0.085 15
Tes penerimaan 42 84% $0.20 8
Reviewer saja 34 68% $0.15 16
Tes dengan reviewer 41 82% $0.28 9
Tes dengan reviewer plus critic 39 78% $0.28 11

Setiap baris bergerbang memakan 54 sampai 86 detik per run, dibanding 33 untuk tanpa gerbang.

Blokir di seluruh lima puluh run terurai sebagai berikut. Tes mengirim agent kembali 28 kali dengan tepat dan lima kali dengan salah. Para reviewer memblokir tiga kali, tidak pernah salah, dan tiga loop menyerah. Seluruh matriks menghabiskan $9.95 pengeluaran API harga list seperti yang dilaporkan CLI, dan sekitar 3,136 detik, atau 52 menit, total waktu worker.

Vonis untuk repositori seperti ini: pertahankan gerbang tes, dengan writer yang bukan implementer dan tes yang tidak bisa diedit agent. Perkirakan sekitar satu blokir salah dari enam, dan beri loop sebuah counter. Gerbang dua reviewer seperti yang ditulis Shopify tidak menggerakkan pass rate di sini, dalam kedua bentuknya. Kalau tetap dipakai, pakai sebagai saran di dalam feedback, bukan sebagai syarat lulus.

Satu jebakan di jalan. Dokumentasi menjelaskan sebuah flag bare yang melewati hook, skill, plugin, dan memori untuk panggilan terskrip. Pada login langganan, flag itu hanya membaca API key dan mengembalikan error, sehingga tiap reviewer diisolasi dengan sumber settings kosong dan hook dimatikan.

Batasannya nyata: satu repositori, satu model worker, lima tugas, dua pengulangan per sel. Selisih dua poin antar baris adalah noise. Empat belas poin antara tanpa gerbang dan gerbang tes bukan noise. Gerbang desain tidak dibangun, dan waktu engineer tidak diukur.

Dari empat gerbang Shopify, pada repositori ini, hanya tes yang terbukti berguna. Seluruh kit ada di paket gratis: file settings dengan hook dan deny list, skrip stop, gerbang, command writer dan reviewer beserta skemanya, dan template ledger.

Sumber daya gratis

Sumber

Pertanyaan yang sering diajukan

Gerbang AI Shopify mana dari keempatnya yang layak dibangun ulang di Claude Code?
Gerbang tes penerimaan. Pada 50 run di tinydb, gerbang ini menaikkan pass rate dari 70% ke 84%, sedangkan gerbang dua reviewer tidak menggesernya (68% sendirian, 82% setelah tes).
Bagaimana cara mencegah Claude Code mengatakan sudah selesai sebelum tes lulus?
Tambahkan Stop hook di settings proyek yang menjalankan tes penerimaan dan keluar dengan kode 2 saat gagal. Claude Code memblokir akhir giliran dan mengirim apa pun yang ditulis skrip ke standard error kembali ke agent sebagai alasannya.
Apakah Stop hook benar-benar bisa memaksa Claude Code terus bekerja?
Tidak sepenuhnya. Dokumentasi hooks mencantumkan batas 8 blokir berturut-turut yang di-reset pada setiap pemanggilan tool, timeout default 600 detik yang tidak menghasilkan keputusan, dan flag stop_hook_active yang disarankan untuk diperiksa. Tambahkan counter blokir sendiri agar loop berakhir dengan terduga.
Apakah dua reviewer kode AI independen memperbaiki hasil agent?
Tidak dalam tes ini. Dua reviewer Sonnet mencetak 68% sendirian dan 82% setelah tes, dua poin di bawah masing-masing baseline, karena mereka menilai crash yang nyata sebagai minor di dua run. Sebuah paper mengukur pola yang sama di LiveCodeBench: 77% zero-shot, 75% dengan dua reviewer, 87% dengan reviewer plus critic.
Berapa biaya tiap gerbang per run di Claude Code?
Biaya API harga list per run adalah $0.085 tanpa gerbang, $0.20 dengan tes penerimaan, $0.15 dengan reviewer saja, dan $0.28 dengan tes plus reviewer. Run bergerbang memakan 54 sampai 86 detik dibanding 33.
Bagaimana cara agar agent tidak membaca tes penerimaan yang tersembunyi?
Simpan tes di luar pohon repositori dan tolak pembacaan skrip hook serta file tes di settings. Agent kemudian melihat assertion yang gagal tetapi tidak pernah melihat file-nya.

Video terkait