Kenapa Selftest R97 Gagal Saat Audit Berjalan
Audit meng-hash ulang setelah render jalan, selftest pun gagal. Artefak turunan harus keluar dari digest kanonik dan urutan verifikasi menentukan arti hash.
Ringkasan
Selftest R97 gagal gara-gara audit menghitung digest kanonik setelah render, padahal render ngubah isi direktori yang lagi di-hash, jadi hashnya salah bukan karena kontennya. Solusinya, artefak turunan kayak nav.json dan pages.json dikeluarin dari digest; yang dijaga cuma sumber kebenarannya. Fixture selftest yang flake juga diganti mutasi berbasis path, checksum di-freeze ulang biar jejaknya jelas.
Selftest R97 gagal dan layar penuh error yang membingungkan. Bukan logika bisnis yang rusak. Setelah menelusuri log eksekusi, penyebabnya aneh: perintah audit dalam pipeline blueprint ternyata menghitung ulang digest kanonik SETELAH menjalankan check dan render, bukan sebelumnya. Render yang menyentuh artefak ikut mengubah isi direktori yang sedang di-hash. Jadi hash-nya salah bukan karena konten berubah, tapi karena urutan eksekusi mengubah arti hash itu sendiri.
Tebakan pertama saya salah total. Saya mengira memasukkan lebih banyak file ke dalam perhitungan hash membuat integritas makin kuat. Logikanya, makin banyak yang diawasi, makin kecil celah yang lolos. Kenyataannya justru sebaliknya: file turunan yang ikut di-hash hanya menciptakan noise, karena barang itu berubah sendiri tanpa ada yang menyentuh sumber kebenarannya.
Memisahkan sumber kebenaran dari artefak turunan
Keputusan desainnya tegas: artefak turunan seperti nav.json dan pages.json keluar dari digest kanonik. Drift pada file-file itu sudah tertutup perbandingan byte BLUEPRINT.md di tahap audit. Mengunci file hasil generate sama saja dengan mengunci bayangan, bukan bendanya.
Pola ini mirip cara kerja dokumentasi besar. Terjemahan Sphinx berupa katalog pesan yang dikompilasi ke direktori locale, dan hasil build-nya adalah artefak turunan yang diregenerasi dari sumber [2]. Nggak ada gunanya meng-hash hasil kompilasi; yang perlu dijaga integritasnya adalah sumbernya.
Supaya mekanismenya jalan, render kini check-first dan dijamin byte-stable untuk BLUEPRINT.md, nav.json, dan pages.json. Sementara keluaran stdout dari check dan render internal disembunyikan lewat StringIO, supaya keluaran JSON audit tetap bersih dan gampang diparsing. Satu baris warning liar di stdout cukup untuk membuat parser JSON audit tersedak berjam-jam.
Memperbaiki selftest yang flake
Masalah kedua ada di fixture. Fixture selftest R97 lama pakai substitusi string escaped-brace, dan pendekatan itu flake di bash 5.2.37, terutama di konteks fungsi. Perilaku parsing string yang beda antar versi shell adalah resep bencana untuk pipeline yang harus deterministik. Kuganti ke mutasi berbasis path lewat helper mutate: lebih panjang sedikit, tapi hasilnya bisa diprediksi di lingkungan mana pun.
Sebagai bagian dari perbaikan, checksum selftest di-freeze ulang dari eb512923 menjadi 7e106fa4, dengan kolom prev_selftest_sha256 sebagai jejak. Kalau nanti ada yang bertanya kenapa hash-nya berubah, jawabannya sudah tercatat di file itu sendiri, bukan cuma di kepala saya atau di riwayat chat.
Kontrak yang dipegang test
Pelajaran terbesarnya soal batas verifikasi: masukkan hanya sumber kebenaran ke dalam digest, keluarkan artefak turunan yang bisa diregenerasi, dan pastikan langkah verifikasi nggak mengubah hal yang sedang diverifikasi.
Batas checksumnya juga perlu diingat. Checksum andal mendeteksi korupsi tak sengaja karena peluang dua berkas ber-digest identik sangat kecil, tapi dia bukan pelindung dari manipulasi disengaja [4]. Kalau input hash bisa berubah tanpa terkendali, nilai hash itu kehilangan arti. Untuk membaca konstanta konfigurasi dari source Python, jalurnya ast.literal_eval: dia hanya mengevaluasi struktur literal seperti string, number, tuple, list, dict, set, boolean, None, dan Ellipsis [1], jadi proses validasi nggak membuka celah eksekusi kode tersembunyi.
Kaitannya dengan salinan paralel: di workflow terdistribusi, developer kedua wajib merge sebelum push supaya nggak menimpa kerja developer pertama, dan drift antar salinan memang perlu dideteksi, bukan dianggap nggak mungkin [3]. Render yang mengubah direktori di tengah audit itu sama Persisnya seperti developer yang menyunting kode orang lain tanpa izin.
Prinsip terakhir saya: keputusan desain paling kuat adalah yang dipegang test, bukan yang hanya ditulis di komentar. Keputusan mengeluarkan nav.json dan pages.json dari digest kanonik sengaja dibiarkan diuji oleh selftest. Test adalah kontrak yang nggak bisa dinegosiasikan oleh manusia yang sedang buru-buru.