Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.
01Kenapa instruksi saja tidak cukup mencegah agen meng-skip tes?
Karena aturannya dievaluasi oleh hal yang dibatasinya, pelanggarannya tidak terlihat — tes yang di-skip tidak menggagalkan suite — dan ia bersaing dengan tenggat pendaratan yang jauh lebih konkret. Sebuah hook berjalan sebelum perintahnya, membandingkan dua fakta, dan mengembalikan keputusan yang tidak bisa ditafsir ulang agen.
02Apa yang sebenarnya perlu diperiksa sebuah merge gate?
Jaga tetap sempit dan mekanis: jumlah tes tidak turun dibanding branch basis, tidak ada penanda skip atau focus baru di diff, pipeline hijau pada commit terakhir, dan ukuran diff-nya di bawah batas yang Anda minta. Empat pemeriksaan, tanpa penilaian mutu kode, semuanya bisa diverifikasi manusia dalam hitungan detik.
03Titik hook mana yang sebaiknya dipakai gate-nya?
Yang menyala sebelum panggilan tool, bukan sesudahnya. Percobaan pertama saya memakai hook pasca-verifikasi, yang berjalan setelah merge-nya sudah terjadi dan menyusutkan gate-nya menjadi pelapor fakta. Gate-nya harus bisa mengembalikan keputusan memblokir, bukan sekadar observasi.
04Apa yang terjadi kalau skrip gate-nya sendiri gagal?
Itu keputusan yang harus Anda ambil secara sengaja dan tuliskan. Gate yang diam-diam mengizinkan saat error tidak bisa dibedakan dari tidak ada gate, dan gate yang memblokir pada setiap error akan dimatikan oleh siapa pun yang sedang bertugas. Pilih satu, dokumentasikan, dan uji jalur error-nya.
05Apakah membiarkan agen me-merge pekerjaannya sendiri pernah masuk akal?
Dengan radius ledakan yang kecil, ya. Ia cocok untuk pustaka dengan suite tes yang kuat di balik gate yang sempit, token ber-scope repositori, check platform yang diwajibkan, dan kebiasaan membaca commit yang ter-merge secara berkala. Ia tidak cocok untuk service yang men-deploy ke produksi saat merge.
Kalau sebuah agen me-merge pull request-nya sendiri, mekanisme pengamannya tidak bisa berupa instruksi — ia harus berupa kode yang tidak bisa dibujuk agen. Hook pra-tool yang menyadap perintah merge lalu memblokirnya ketika jumlah tes turun atau ada tes yang di-skip menangkap persis kegagalan yang tidak tertangkap aturan kejujuran.
Begitu agen coding saya mulai me-merge pull request-nya sendiri, satu pertanyaan menjadi lebih tajam: apa yang mencegahnya membuat tes lolos dengan cara mudah? Bukan karena niat jahat — model yang tertekan untuk menyelesaikan akan meng-skip tes yang membangkang sebagaimana developer yang lelah mungkin melakukannya, dan ia akan menulis pesan commit yang sangat masuk akal untuk menjelaskan alasannya.
Instruksi bukan jawaban untuk itu, karena penalaran yang sama yang memutuskan meng-skip tes juga yang memutuskan apakah instruksinya berlaku. Jawabannya harus deterministik, dan harus duduk di antara agen dan merge-nya.
Kenapa aturan kejujuran tidak cukup
Versi pertama saya adalah satu paragraf di berkas instruksi agen: jangan pernah menonaktifkan tes agar suite-nya lolos. Itu aturan yang baik dan bukan sebuah kendali, karena tiga alasan.
Ia dievaluasi oleh hal yang dibatasinya. Model yang sudah meyakinkan dirinya bahwa sebuah tes rapuh juga sudah meyakinkan dirinya bahwa aturannya tidak berlaku di sini.
Ia tidak terlihat ketika dilanggar. Tes yang di-skip tidak menggagalkan suite — justru itulah seluruh intinya — jadi tidak ada apa pun di hilir yang menyadarinya.
Ia bersaing dengan instruksi lain. Di bawah tenggat pendaratan, selesaikan dan jujurlah saling menegang, dan tenggatnya lebih konkret di antara keduanya.
Sebuah hook tidak punya sifat-sifat itu. Ia berjalan sebelum perintahnya, ia membandingkan dua fakta, dan ia mengembalikan keputusan yang tidak bisa ditafsir ulang agen.
Perlindungan di sisi platform adalah cincin luarnya: check yang diwajibkan membuat pipeline merah memblokir tombol merge. Yang tidak bisa ia lihat adalah pipeline hijau yang menjadi hijau karena tes yang gagal dihapus. Tangkapan layar: Tarepan / Wikimedia Commons, CC BY-SA 4.0
Gate-nya sendiri
Hook-nya menyala pada setiap panggilan tool, mengabaikan semua yang bukan merge, lalu memeriksa dua hal yang keduanya murah dihitung dan sulit dibantah.
#!/usr/bin/env bash
# merge-gate.sh — runs BEFORE the agent's merge command is executed.
# Deterministic, boring, and impossible to argue with.
set -euo pipefail
cmd=$(jq -r '.tool_input.command' <<< "$(cat)")
[[ "$cmd" == *"pr merge"* ]] || { echo '{}'; exit 0; }
deny() {
jq -nc --arg r "$1" '{action:"block", reason:$r}'
exit 0
}
# 1. The branch must not have fewer tests than main.
base=$(git show origin/main:package.json >/dev/null 2>&1 && \
git grep -c -E "\b(it|test)\(" origin/main -- 'src/**/*.test.ts' | \
awk -F: '{s+=$NF} END {print s+0}')
head=$(git grep -c -E "\b(it|test)\(" HEAD -- 'src/**/*.test.ts' | \
awk -F: '{s+=$NF} END {print s+0}')
(( head < base )) && deny "test count dropped from $base to $head"
# 2. No test may have been disabled to make the suite pass.
git diff origin/main...HEAD -- 'src/**/*.test.ts' \
| grep -E '^\+.*(\.skip|\.only|xit\()' \
&& deny "branch adds skipped or focused tests"
echo '{}' # allow
Perhatikan apa yang tidak ia coba lakukan. Ia tidak menilai mutu kode, tidak menimbang apakah perubahannya ide bagus, dan tidak membaca diff untuk menebak maksud. Setiap pemeriksaannya adalah perbandingan antara branch dan basisnya yang bisa diverifikasi manusia dalam sepuluh detik. Kesempitan itulah yang membuatnya bisa dipercaya.
Pilih titik hook yang menyala sebelum aksinya, bukan sesudahnya. Percobaan pertama saya memakai hook pasca-verifikasi, dan itu terlambat: saat ia berjalan, merge-nya sudah terjadi dan gate-nya menyusut menjadi pelapor fakta.
Menguji gate-nya, bukan hanya agennya
Pagar pengaman yang belum pernah terlihat memblokir apa pun hanyalah dugaan. Saya memverifikasi yang ini dua arah sebelum memercayainya: branch yang sengaja menghapus sebuah tes diblokir, dan branch yang bersih ter-merge normal.
Kasus negatifnya sama pentingnya dengan yang positif. Gate yang memblokir segalanya cepat dinonaktifkan oleh siapa pun yang sedang bertugas, dan gate yang menyala pada merge yang sah melatih Anda melewatinya — dan itu lebih buruk daripada tidak punya gate, karena Anda juga kehilangan ilusi perlindungannya.
Buat mode kegagalan gate-nya eksplisit. Kalau hook-nya sendiri error — dependensi hilang, perintah git yang gagal di clone baru — putuskan secara sengaja apakah itu memblokir atau mengizinkan, lalu tuliskan keputusannya. Gate yang diam-diam mengizinkan saat error tidak bisa dibedakan dari tidak ada gate sama sekali.
Apa yang perlu di-gate
Empat pemeriksaan menutup cara-cara realistis agen tanpa pengawasan menghasilkan branch hijau yang seharusnya tidak ter-merge. Keempatnya mekanis.
Pemeriksaan
Yang ia tangkap
Kenapa aman diotomatiskan
Jumlah tes tidak turun
Tes dihapus agar suite-nya lolos
Perbandingan hitungan terhadap branch basis, tanpa penilaian apa pun
Tidak ada penanda skip atau focus baru
Tes dinonaktifkan atau dipersempit alih-alih diperbaiki
Grep atas baris yang ditambahkan di diff; positif palsunya jarang dan kentara
Pipeline hijau pada commit terakhir
Merge dicoba sebelum check-nya selesai
Platformnya sudah tahu jawabannya; gate-nya sekadar menolak mengabaikannya
Ukuran diff di bawah batas
Run yang diam-diam menulis ulang satu berkas utuh alih-alih membuat perubahan kecil
Ambang jumlah baris yang Anda tetapkan sekali, sesuai cakupan yang Anda minta
Saya tidak akan menambahkan yang kelima. Setiap pemeriksaan tambahan adalah satu peluang lagi memblokir merge yang sah pada pukul tiga pagi, dan nilai gate ini justru berasal dari kesempitannya sehingga tak seorang pun pernah tergoda mematikannya.
Dua cincin dengan tugas berbeda. Pipeline membuktikan kodenya bekerja; merge gate membuktikan branch-nya tidak mengubah arti bekerja. Tak satu pun menggantikan yang lain. Diagram: Liao / Wikimedia Commons, CC BY-SA 3.0
Sisa selubung keamanannya
Gate-nya satu lapisan. Empat lapisan lain membuat merge-sendiri bisa dipertanggungjawabkan alih-alih sembrono.
Batasi cakupan token. Token klasik ber-scope repositori cukup untuk branch, pull request, dan merge, dan secara sengaja tidak cukup untuk menghapus repositori.
Wajibkan pipeline sebagai check di sisi platform, agar build merah memblokir merge bahkan kalau hook-nya entah bagaimana terlewati.
Jaga radius ledakannya kecil. Merge-sendiri cocok untuk pustaka dengan suite tes yang kuat; tidak cocok untuk service yang men-deploy ke produksi saat merge.
Baca commit yang ter-merge secara rutin. Tidak setiap commit, tetapi cukup agar Anda akan menyadari pola tes yang diam-diam dilemahkan.
Layak jujur bahwa ini tetap pertukaran risiko. Model gratis yang sederhana me-merge ke pustaka yang sudah terbit, hanya dipagari tes lokal dan aturan kejujuran, adalah keputusan yang saya ambil dengan mata terbuka — dan gate inilah alasan saya merasa nyaman mengambilnya.
Membangun milik Anda sendiri
Empat langkah, dalam urutan yang memberi Anda gate yang bekerja dalam satu sore.
Temukan titik hook di runtime Anda yang menyala sebelum panggilan tool, dan pastikan ia bisa mengembalikan keputusan memblokir, bukan sekadar observasi.
Tulis pemeriksaan paling sempit yang bisa Anda pertanggungjawabkan — perbandingan jumlah tes adalah titik awal terbaik — dan tidak lebih.
Buktikan ia memblokir dengan mendorong branch yang sengaja menghapus sebuah tes, dan buktikan ia mengizinkan dengan me-merge branch yang bersih.
Tambahkan pemeriksaan kedua hanya setelah yang pertama berjalan sungguhan selama seminggu tanpa positif palsu.
Satu detail penggelaran pernah menggigit saya: skrip hook-nya tinggal di dalam image, jadi mengubahnya butuh rebuild alih-alih menyalinnya ke container yang sedang berjalan. Gate yang hanya ada di container tempat Anda bereksperimen bukanlah gate.
Membiarkan agen me-merge pekerjaannya sendiri masuk akal ketika yang berdiri di antara ia dan branch utama adalah kode, bukan janji. Jaga gate-nya sempit, uji kedua hasilnya, buat mode kegagalannya eksplisit, dan ia mengubah kepercayaan berjumlah tidak nyaman menjadi kepercayaan kecil yang bisa diverifikasi.