Merge Gate Deterministik untuk Agen AI yang Merge Sendiri

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.
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.
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.
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.
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.

Ringkasan Utama
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.
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.
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.

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 '{}' # allowPerhatikan 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.
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.
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.

Gate-nya satu lapisan. Empat lapisan lain membuat merge-sendiri bisa dipertanggungjawabkan alih-alih sembrono.
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.
Empat langkah, dalam urutan yang memberi Anda gate yang bekerja dalam satu sore.
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.