Spec-Driven Development Bersama AI Coding Agent
Saya membangun portal manajemen vendor dalam sekitar enam minggu, sebagai satu-satunya engineer di repositori itu. Sebagian besar kode ditulis AI coding agent. Saya membuka semua 179 pull request dan menggabungkan 142 di antaranya.
Dengan pembagian kerja itu, proyek dapat diselesaikan, tetapi proses review-nya memiliki kelemahan: saya tidak didampingi reviewer manusia kedua.
Proyeknya berjalan dari 21 Agustus sampai 4 Oktober 2026 untuk Metrodata. Portal ini menangani onboarding vendor, purchase order, penerimaan barang, invoice dengan verifikasi pajak, dan approval bertingkat. Stack-nya FastAPI, PostgreSQL, dan Next.js, di-deploy ke Azure App Service. Di akhir periode, ada 51 spec bernomor, 21 domain backend, dan 109 migrasi Alembic.
Produk ini tidak memiliki fitur AI. GitHub Copilot dan Claude saya gunakan untuk implementasi, sementara saya menulis spec, merancang arsitektur, meninjau PR, dan memutuskan perubahan yang digabungkan. Agar pembagian kerja ini berjalan, saya harus mendefinisikan pekerjaannya sebelum agent mulai menulis kode. Meski begitu, beberapa bug serius tetap lolos.
Alasan Menulis Spec Sebelum Kode
Agent dapat menulis approval engine yang tampak masuk akal dalam waktu singkat. Kesesuaiannya dengan proses bisnis tetap harus saya periksa. Saya perlu menentukan apa yang dianggap "benar" sekaligus menyiapkan cara untuk mengujinya.
Ketika agent mengerjakan sebagian besar penulisan kode, penentuan kebutuhan dan pemeriksaan hasil menjadi bottleneck. Keputusan tentang keduanya sulit dijadikan acuan jika hanya tersimpan dalam riwayat chat yang panjang.
Commit pertama saya berisi blueprint, bukan kode. Saya menulisnya dengan GitHub Spec Kit: lima belas spec untuk domain, identitas, data, dan deployment, serta constitution berisi aturan yang wajib diikuti setiap agent. Spec fitur berikutnya masing-masing punya ID task, acceptance criteria, dan business rule. Di akhir proyek, repositori sudah merujuk ribuan ID.
Selama masih berupa dokumen, desain lebih mudah diubah. Pada hari kedua, saya mengganti Cosmos DB dengan PostgreSQL di blueprint karena domainnya membutuhkan integritas relasional dan constraint. Alasannya saya catat di decision record.
Pada hari keempat, saya menjalankan adversarial consistency review dan menemukan 24 defect di seluruh spec, kebanyakan berupa kontradiksi antarspec. Semuanya saya perbaiki sebelum agent memakai spec itu untuk implementasi. Kedua perubahan tersebut selesai dengan menyunting dokumen selama satu siang, tanpa perlu migrasi.
Alur Kerja
Setiap fitur melewati jalur yang sama:
- Saya menulis spec bernomor dengan ID task, acceptance criteria, dan business rule.
- Agent membacanya bersama constitution dan file konvensi agent.
- Agent mengerjakannya di git worktree sendiri, lalu saya membuka pull request untuk branch-nya.
- CI gate memeriksa pull request itu.
- Saya meninjau dan memutuskan apakah pull request itu di-merge.
- Deploy ke Azure App Service hanya berjalan setelah CI hijau.
Constitution dan file konvensi berisi aturan yang tidak boleh ditafsirkan ulang oleh agent. Misalnya, two-boundary rule: Next.js hanya menangani presentasi dan backend-for-frontend, sementara seluruh business logic ada di FastAPI. Permission wajib dihitung ulang berdasarkan database pada setiap request, tanpa mengandalkan permission yang dikirim client.
Untuk tahap besar, saya menjalankan beberapa agent secara paralel di git worktree terpisah, lalu menggabungkan branch mereka melalui pull request integrasi. CI gate membantu saya meninjau perubahan gabungannya.
Selain typecheck, lint, build, bundle-size budget, dan ruff, CI mengecek keterkaitan pekerjaan dengan ID spec. Ada juga drift check untuk TypeScript API client yang di-generate, secret scan, architecture test, dan extended tier dengan service PostgreSQL 16 sungguhan. Deploy hanya berjalan setelah CI hijau.
Sebagian perubahan tidak lolos gate. Dari run CI terbaru yang tercatat sejak 1 September, 140 dari 488 gagal. Penyebabnya tidak saya klasifikasikan, sehingga saya tidak dapat membedakan kegagalan akibat kesalahan agent, kesalahan saya sendiri, atau gangguan infrastruktur. Jumlah kegagalan itu saja belum cukup untuk menentukan penyebab dan penanggung jawabnya.
Perubahan Alur Kerja Menjadi Berbasis Purchase Order
Pada rancangan awal, alur kerja disusun berdasarkan dokumen penerimaan barang. Setelah revisi proses bisnis disetujui pada 11 September, purchase order menjadi acuan utama alurnya.
Dengan perubahan ini, vendor dan staf internal bekerja dalam satu PO workspace. Penggantian dokumen dilakukan pada tempat yang sama, dan referensi disimpan secara persis, menggantikan aturan "dokumen terbaru yang menang". Pada 25 September, product owner juga meminta agar approval matrix yang bisa dikonfigurasi dihapus. Setelah itu, rute approval ditentukan di kode.
Saya menulis spec bernomor baru untuk perubahan tersebut. Perubahan menjadi berbasis purchase order diterapkan antara 9 hingga 16 September. Penghapusan approval matrix memakai migrasi expand and contract agar data lama tetap dapat dibaca selama peralihan ke routing baru.
Bagi saya, membaca diff dokumen sebelum diff kode membantu memperjelas perubahan kebutuhan. Saya dapat melihat acceptance criteria mana yang digantikan, lalu membatasi tugas agent berdasarkan spec baru. Ledger guard memeriksa apakah pekerjaan memiliki rujukan ke requirement dan menandai yang belum memiliki rujukan.
Manfaat itu baru penilaian saya sendiri. Penghematan waktunya belum diukur, dan saya tidak memiliki pembanding.
Perubahan tersebut juga membutuhkan cleanup. Kode dari spec lama menjadi tidak terjangkau dan baru saya hapus dalam putaran khusus test debt dan dead code pada 4 Oktober. Tugas untuk agent sudah menjelaskan apa yang harus dibangun, tetapi belum mencakup kode lama yang perlu dihapus.
Sistem yang Dibangun dengan Agent
Two-boundary rule menentukan alur request setelah login:
- Vendor dan approver internal memakai portal Next.js. Portal ini menyajikan UI sekaligus menjadi backend-for-frontend, dan menyimpan sesi dalam sealed HttpOnly cookie.
- Staf login dengan Entra ID lewat backend FastAPI, yang menulis sesi ke PostgreSQL.
- Setiap request API dari portal masuk ke backend FastAPI lewat REST. Backend menghitung ulang permission user berdasarkan database pada setiap request, sehingga cookie cukup menyimpan informasi yang dibutuhkan UI untuk gating.
- Browser mengunggah dokumen langsung ke Blob Storage, dan backend mengolahnya di sana.
Bug cookie yang saya jelaskan berikutnya terjadi pada langkah 1 dan 3, sedangkan bug terkait waktu commit pertama kali terlihat pada langkah 2.
Bug yang Tetap Lolos
Repositori tidak mencatat apakah tiap baris ditulis oleh saya atau agent. Sebagian besar kode ditulis agent, dan semuanya saya setujui. Kegagalan berikut tetap tanggung jawab saya.
CI Hijau Karena Test Tidak Berjalan
Integration tier membutuhkan URL database. Kalau URL tidak ada, pytest melewati tier tersebut dan CI tetap hijau.
Saat suite lengkap dijalankan terhadap PostgreSQL sungguhan, muncul 45 failure dan 301 error, dengan 5 defect nyata di antaranya. Saya memperbaiki kelimanya, membuat kebutuhan database eksplisit, dan mengoreksi klaim tentang apa yang dicek CI.
Laporan CI tidak membedakan tier yang di-skip dari tier yang lolos. Karena agent memakai laporan itu sebagai feedback, keduanya tidak dapat dibedakan saat memperbaiki kode.
Cookie Lolos Test, Tetapi Terlalu Besar untuk Browser
Login memakai sealed HttpOnly cookie yang membungkus token bertanda tangan. Token itu membawa permission user.
Dengan 58 permission grant, cookie mencapai 4.234 sampai 4.491 byte, melewati batas sekitar 4 KB yang diterima browser. Login staf mengembalikan 500. Fixture test-nya memakai signature palsu sepanjang 9 karakter, jadi masalah ukuran ini tidak terlihat.
Saya mencoba chunking cookie, lalu kompresi yang ternyata tidak tersedia di edge runtime. Namun, masalah desainnya tetap perlu diperbaiki: backend sudah menghitung ulang permission pada setiap request, sehingga token cukup menyimpan kode yang dibutuhkan UI untuk gating. Setelah isinya dibatasi pada kode tersebut, ukuran cookie menjadi 2.083 byte.
Pengecekan Sesi Mendahului Commit Transaksi
Setelah login lewat Entra ID, callback mengembalikan 200, tetapi pengecekan sesi berikutnya mendapat 401: "session does not exist".
Saat memeriksa melalui koneksi database kedua, saya menemukan baris sesi tersebut, tetapi baru tersedia setelah pengecekan dari browser. Dependency FastAPI yang mengelola transaksi melakukan commit saat teardown. Pada versi yang saya pin, teardown berjalan setelah response terkirim, sehingga browser mengecek sesi sebelum transaksi selesai di-commit.
Urutan ini berlaku untuk semua endpoint yang menulis data, bukan hanya login. Perbaikannya melakukan commit sebelum mengirim response dan gagal secara eksplisit kalau langkah itu tidak ada.
Ketiga masalah ini berasal dari konfigurasi CI, batas browser, dan lifecycle framework, bukan kekurangan pada spec. Detail tersebut memang tidak dijelaskan di spec, sementara agent mengerjakan implementasi berdasarkan test yang saya sediakan. Kesalahan pada environment test pun tidak terdeteksi selama proses itu.
Praktik yang Dipertahankan dan Perubahan Berikutnya
Saya tetap akan memakai spec bernomor dengan ID task, acceptance criteria, dan business rule, lalu mengujinya lewat adversarial review sebelum coding. Saya juga akan mempertahankan satu constitution dan file konvensi untuk semua agent, aturan arsitektur yang dijaga test, CI untuk traceability dan kontrak, serta merge gate yang dipegang manusia.
Untuk autentikasi, approval, dan alur terkait pembayaran, saya akan melibatkan reviewer manusia kedua agar peninjauannya tidak hanya bergantung pada saya.
Perubahan lainnya konkret: CI fail-closed sejak awal, sehingga tier yang di-skip membuat build gagal; fixture yang bentuk dan ukurannya mirip production; serta smoke test di environment ter-deploy dengan identity provider sungguhan sebelum login dianggap selesai. Setiap spec yang menggantikan pekerjaan lama juga perlu menyertakan penghapusan kode yang sudah tidak dipakai.
Pengukurannya pun perlu saya perbaiki. Saya tidak mencatat waktu per spec, defect berdasarkan asalnya, atau baseline tanpa agent. Jadi proyek ini tidak memberi dasar untuk klaim produktivitas. Lain kali, saya akan mencatatnya sejak spec pertama.
Sekarang saya memakai GitHub Spec Kit dengan constitution berversi di setidaknya sembilan repositori. Pada proyek berikutnya, saya akan tetap mendefinisikan pekerjaan agent secara jelas agar hasilnya dapat ditinjau. Saya juga perlu memastikan semua pemeriksaan benar-benar berjalan sebelum mengandalkan status CI hijau.