Strategi verifikasi arsip gambar publik perlu dirancang sebagai workflow engineering, bukan sekadar kumpulan test acak. Pada arsip gambar domain publik, regresi sering muncul bukan karena aplikasi gagal total, melainkan karena metadata berubah diam-diam, thumbnail bergeser ukuran atau orientasinya, hasil pencarian menurun relevansinya, deduplikasi terlalu agresif, atau status lisensi dan atribusi tertimpa saat ingest ulang.

Untuk mencegahnya, tim perlu memecah verifikasi ke beberapa lapisan: unit test untuk aturan transformasi, integration test untuk database, storage, dan search index, end-to-end test untuk alur ingest sampai publish, dan post-deploy verification untuk mendeteksi masalah di lingkungan nyata. Kunci utamanya adalah memakai golden dataset, contract test pada importer, checksum untuk integritas file, serta snapshot yang dipakai secara hati-hati hanya pada output yang stabil.

Risiko regresi yang khas pada arsip gambar domain publik

Arsip seperti Public Domain Image Archive umumnya memproses data dari banyak sumber: koleksi institusi, dump metadata, file gambar resolusi tinggi, dan pembaruan lisensi atau atribusi. Masalahnya, sebagian besar regresi tidak terlihat sebagai error eksplisit.

  • Ingest metadata: field tanggal, creator, source URL, identifier, atau rights statement berubah format atau hilang saat parser diperbarui.
  • Thumbnail generation: orientasi EXIF tidak diterapkan, ukuran hasil tidak konsisten, transparansi PNG hilang, atau crop berubah tanpa sengaja.
  • Pencarian: tokenisasi judul berubah, boosting field rusak, filtering lisensi salah, atau dokumen tidak terindeks setelah reingest.
  • Deduplikasi: hash file benar tetapi metadata berbeda; atau dua karya berbeda dianggap duplikat karena judul mirip.
  • Lisensi/atribusi: perubahan rules normalisasi menghapus atribusi penting, menurunkan confidence lisensi, atau menimpa peringatan bahwa sumber perlu ditinjau manual.

Karena itu, strategi verifikasi harus memeriksa kebenaran data, bukan hanya status sukses pipeline.

Desain test pyramid untuk workflow arsip gambar

Kesalahan umum adalah terlalu bergantung pada test end-to-end yang lambat dan rapuh. Untuk workflow arsip gambar, test pyramid tetap relevan: banyak unit test, cukup integration test, sedikit end-to-end test yang sangat representatif.

1. Unit test: aturan kecil yang menentukan kualitas data

Gunakan unit test untuk logika yang deterministik dan tidak perlu storage atau jaringan:

  • normalisasi metadata (trim, fallback field, parsing tahun, canonicalization license string),
  • pemilihan judul utama dari beberapa alternatif,
  • aturan atribusi, misalnya kapan field creator ditampilkan atau disembunyikan,
  • perhitungan checksum manifest,
  • matching sederhana untuk deduplikasi berbasis identifier atau hash.

Unit test harus kecil, cepat, dan eksplisit. Jika aturan berubah, tim bisa melihat dengan tepat rule mana yang pecah.

2. Integration test: verifikasi batas sistem

Integration test dipakai saat ada interaksi antar komponen:

  • importer menulis ke database,
  • worker membuat thumbnail dan mengunggah ke object storage,
  • dokumen masuk ke search index,
  • job deduplikasi memperbarui relasi antar aset.

Di level ini, fokusnya adalah kontrak antar subsistem: skema data, format event, idempotency job, dan konsistensi hasil akhir.

3. End-to-end test: sedikit tapi mencakup jalur kritis

Pilih beberapa alur yang paling berisiko:

  1. ingest record baru dari sumber eksternal,
  2. unduh file master,
  3. generate derivative seperti thumbnail dan preview,
  4. indeks ke mesin pencari,
  5. record tampil di UI/API dengan lisensi dan atribusi yang benar.

Jangan jadikan E2E sebagai tempat menguji semua kombinasi metadata. Itu membuat pipeline lambat dan flaky.

Golden dataset: fondasi verifikasi regresi data

Untuk arsip gambar, golden dataset adalah kumpulan record dan file contoh yang sengaja dipilih untuk mewakili kasus nyata. Ini lebih berguna daripada data dummy acak karena bisa menjadi acuan stabil ketika parser, image pipeline, atau search logic berubah.

Apa isi golden dataset yang baik

  • gambar JPEG dengan orientasi EXIF berbeda,
  • PNG transparan, TIFF besar, dan file dengan metadata minim,
  • record dengan creator tunggal, banyak creator, atau creator tidak diketahui,
  • lisensi yang jelas publik domain dan lisensi yang ambigu yang harus masuk review,
  • dua file identik dengan nama berbeda,
  • dua karya berbeda dengan judul mirip untuk menguji false positive dedup,
  • record dengan karakter non-ASCII, diakritik, aksara non-Latin, dan emoji jika pipeline harus tahan input aneh,
  • record dengan field kosong, URL rusak, atau tanggal parsial seperti hanya tahun.

Cara memakai golden dataset

Simpan dataset sebagai artefak versioned di repository kecil terpisah atau bucket internal yang immutabel. Untuk tiap record, simpan:

  • input mentah dari sumber,
  • hasil normalisasi yang diharapkan,
  • checksum file,
  • fingerprint thumbnail jika relevan,
  • ekspektasi search assertions,
  • flag deduplikasi yang diharapkan,
  • status lisensi/atribusi yang diharapkan.

Jangan terlalu besar. Tujuannya bukan meniru seluruh arsip, tetapi mewakili kelas risiko yang paling sering rusak.

Contoh struktur manifest golden dataset

{
  "record_id": "sample-1842-plate-7",
  "source": "library-feed-a",
  "input_file": "fixtures/source/sample-1842-plate-7.xml",
  "master_image": "fixtures/images/sample-1842-plate-7.tif",
  "expected": {
    "title": "Plate 7",
    "creator": ["Unknown"],
    "rights_status": "public_domain",
    "attribution_required": false,
    "search_must_match": ["plate 7", "1842"],
    "search_must_not_match": ["restricted"],
    "duplicate_group": null,
    "master_sha256": "",
    "thumbnail": {
      "format": "jpeg",
      "max_width": 400,
      "max_height": 400
    }
  }
}

Manifest seperti ini membantu memisahkan input dari ekspektasi dan mengurangi test yang sulit dipahami.

Contract test untuk importer dan sumber data eksternal

Importer sering menjadi sumber regresi terbesar karena format input dari mitra atau institusi bisa berubah tanpa pemberitahuan. Contract test berguna untuk memastikan importer tetap memahami struktur minimum yang dibutuhkan sistem.

Apa yang diverifikasi contract test

  • field wajib ada atau punya fallback yang jelas,
  • mapping identifier sumber ke identifier internal stabil,
  • license statement dipetakan ke enum internal yang benar,
  • creator, title, date, source URL, dan media URL tidak hilang saat schema input berubah,
  • record yang invalid gagal dengan alasan yang dapat diaudit, bukan diproses diam-diam.

Pola implementasi yang aman

Daripada langsung menguji database, buat importer mengeluarkan canonical intermediate representation. Lalu uji bahwa berbagai format input dipetakan ke representasi internal yang konsisten.

def test_importer_maps_required_fields(feed_fixture):
    record = import_record(feed_fixture("museum_a_minimal.xml"))

    assert record.external_id == "abc-123"
    assert record.title == "Untitled engraving"
    assert record.rights_status in {"public_domain", "needs_review"}
    assert record.source_name == "museum_a"
    assert record.media_url is not None

Dengan pendekatan ini, perubahan storage atau indeks pencarian tidak memaksa semua test importer ikut berubah.

Trade-off contract test

Contract test tidak menjamin sumber eksternal selalu konsisten. Ia hanya menjamin sistem Anda bereaksi dengan cara yang dapat diprediksi terhadap variasi input yang sudah diketahui. Untuk sumber yang sering berubah, tambahkan job sampling harian yang memvalidasi beberapa record nyata dan melaporkan drift schema.

Verifikasi metadata, thumbnail, pencarian, deduplikasi, dan lisensi

Verifikasi ingest metadata

Untuk ingest metadata, jangan hanya memeriksa bahwa record tercipta. Verifikasi juga semantik data:

  • field penting tidak menjadi string kosong,
  • canonical title dipilih dengan rule yang benar,
  • date normalization tidak mengubah makna,
  • rights status tidak turun dari public_domain menjadi null akibat perubahan parser,
  • reingest bersifat idempotent dan tidak menggandakan record.

Tambahkan test untuk partial update. Banyak regresi terjadi saat ingest kedua hanya membawa subset field, lalu nilai lama tertimpa null.

Verifikasi thumbnail generation

Thumbnail sulit diuji jika Anda membandingkan byte file secara mentah, karena encoder berbeda bisa menghasilkan output biner berbeda walau visual setara. Gunakan pendekatan berikut:

  • cek dimensi maksimal dan aspect ratio,
  • cek format output yang diharapkan,
  • cek orientasi hasil,
  • gunakan checksum hanya jika pipeline encoder benar-benar stabil,
  • jika perlu, bandingkan properti visual dasar atau perceptual hash dengan toleransi kecil, bukan byte exact.

Catatan: snapshot file gambar mentah mudah rapuh. Lebih aman menyimpan assertion terhadap properti output daripada keseluruhan biner, kecuali environment image processing Anda sangat terkendali.

Verifikasi pencarian

Search regression sering terlewat karena test hanya memeriksa bahwa dokumen masuk indeks. Yang lebih berguna adalah assertion berbasis perilaku:

  • query tertentu harus menemukan record target,
  • filter rights status harus mengeluarkan item non-publik domain,
  • pencarian judul dengan diakritik dan tanpa diakritik memberi hasil wajar,
  • reingest memperbarui dokumen lama, bukan membuat duplikat indeks.

Jika ranking sangat dinamis, hindari assertion bahwa record harus selalu peringkat pertama. Lebih stabil memeriksa bahwa record muncul dalam top N atau bahwa field tertentu dapat difilter dengan benar.

Verifikasi deduplikasi

Deduplikasi perlu diuji sebagai kombinasi beberapa sinyal:

  • checksum file identik,
  • identifier sumber sama,
  • judul mirip tetapi creator/tahun berbeda,
  • gambar identik dengan metadata lisensi berbeda.

Jangan membiarkan satu sinyal lemah langsung menggabungkan record. Buat test yang memastikan sistem memilih salah satu dari tiga hasil:

  1. duplicate confirmed,
  2. possible duplicate needs review,
  3. not duplicate.

Model ini lebih aman daripada boolean sederhana karena mengurangi kerusakan data akibat merge yang salah.

Verifikasi lisensi dan atribusi

Untuk arsip domain publik, kesalahan lisensi bukan hanya bug data, tetapi juga masalah kebijakan publikasi. Pastikan ada test untuk:

  • mapping berbagai rights statement ke status internal,
  • atribusi tetap tampil jika diwajibkan oleh sumber walau karya berada di domain publik,
  • record ambigu tidak otomatis dipublikasikan sebagai publik domain,
  • perubahan metadata lisensi saat reingest tercatat di audit log atau change history.

Sering kali aturan lisensi berkembang. Simpan rules dalam modul terpisah dan uji dengan tabel kasus agar perubahan bisa direview dengan jelas.

Checksum, integritas file, dan snapshot yang aman

Kapan memakai checksum

Checksum seperti SHA-256 cocok untuk memverifikasi:

  • file master tidak korup saat dipindah antar storage,
  • download dari sumber sesuai manifest yang diharapkan,
  • cache atau reprocessing tidak menghasilkan file yang salah konteksnya.

Checksum sangat baik untuk file integrity, tetapi tidak cukup untuk menilai kualitas visual atau kebenaran metadata.

Snapshot yang aman dipakai

Snapshot test berguna jika output bersifat stabil dan mudah dibaca manusia, misalnya:

  • hasil normalisasi metadata dalam JSON canonical,
  • dokumen yang dikirim ke search index setelah field non-deterministik dihapus,
  • payload API publik yang strukturnya harus dijaga.

Snapshot kurang aman untuk field seperti timestamp, path temporer, ID acak, urutan map yang tidak dijamin, atau output biner hasil encoder. Sebelum snapshot disimpan, lakukan normalisasi:

function sanitizeForSnapshot(doc) {
  return {
    ...doc,
    indexed_at: "<normalized>",
    storage_path: "<normalized>",
    job_id: "<normalized>"
  };
}

Tanpa sanitasi, snapshot akan sering berubah padahal perilaku bisnis tidak berubah.

Mengurangi flaky test pada pipeline file dan jaringan

Pipeline arsip gambar rentan terhadap flaky test karena menyentuh file besar, object storage, queue worker, dan jaringan eksternal. Beberapa langkah berikut biasanya paling efektif.

1. Pisahkan test deterministik dan test yang bergantung jaringan

Semua test rutin di CI sebaiknya berjalan tanpa ketergantungan internet publik. Simulasikan sumber eksternal dengan fixture lokal atau service stub. Test terhadap endpoint nyata bisa dijalankan terpisah sebagai smoke test terjadwal.

2. Gunakan storage lokal atau emulator yang konsisten

Untuk integration test, lebih stabil memakai filesystem sementara atau emulator object storage yang dikontrol sendiri. Yang penting adalah kontrak path, metadata objek, dan alur upload/download bisa diuji tanpa latensi acak.

3. Kendalikan concurrency

Bug pada pipeline async sering muncul karena race condition. Di environment test, batasi jumlah worker atau jalankan queue secara sinkron untuk sebagian test. Sisakan beberapa integration test khusus untuk memeriksa perilaku async sebenarnya.

4. Bekukan waktu dan random seed

Nama file, cache key, atau sorting berbasis timestamp sering membuat hasil test tidak stabil. Gunakan waktu tetap dan seed acak yang konsisten jika pipeline membangkitkan identifier atau sampling.

5. Tambahkan retry hanya di boundary eksternal

Retry boleh dipakai untuk operasi jaringan nyata, tetapi jangan menutupi bug deterministik. Jika test butuh retry agar lolos, biasanya ada masalah sinkronisasi, polling yang salah, atau dependency eksternal yang seharusnya dimock.

6. Polling dengan timeout eksplisit

Untuk menunggu job indexing atau thumbnail selesai, jangan memakai sleep statis yang mudah gagal di runner lambat. Gunakan polling dengan timeout yang jelas.

# pseudo-check dalam CI step
wait_until indexed "sample-1842-plate-7" --timeout 60
wait_until thumbnail_exists "sample-1842-plate-7" --timeout 60

Pendekatan ini lebih tahan terhadap variasi performa daripada sleep 10.

Contoh pembagian test yang bisa diterapkan tim engineering

Unit test

  • normalisasi license statement ke status internal,
  • parsing tanggal parsial,
  • pemilihan title utama,
  • hash manifest dan validasi checksum,
  • aturan klasifikasi dedup berdasarkan sinyal input.

Integration test

  • importer membaca fixture sumber lalu menulis record canonical ke database,
  • worker thumbnail membaca file master dan menaruh derivative ke storage,
  • dokumen hasil transformasi masuk ke search index,
  • reingest record yang sama tidak membuat duplikat data atau dokumen indeks.

End-to-end test

  • feed baru diproses penuh dari ingest hingga tampil di endpoint publik,
  • perubahan lisensi dari sumber memperbarui API dan UI,
  • dua file identik masuk dan sistem menandai possible duplicate tanpa merge otomatis.

Verifikasi pasca-deploy

  • sampling beberapa record golden di production untuk cek API, search, dan asset URL,
  • bandingkan jumlah dokumen terindeks vs jumlah record publishable,
  • cek rasio job gagal thumbnail dan ingest setelah deploy,
  • audit perubahan rights status dalam jendela waktu deploy.

Verifikasi pasca-deploy penting karena sebagian masalah baru muncul pada volume data nyata, kredensial storage sebenarnya, atau konfigurasi index production.

Checklist CI untuk mencegah regresi data

Berikut checklist CI yang praktis untuk workflow arsip gambar publik:

  1. jalankan unit test untuk normalisasi metadata, lisensi, dan dedup rules,
  2. jalankan contract test untuk semua importer aktif,
  3. proses golden dataset kecil end-to-end di environment ephemeral,
  4. validasi checksum file fixture dan artefak penting,
  5. verifikasi thumbnail assertions: dimensi, format, orientasi,
  6. jalankan search assertions terhadap query representatif,
  7. cek idempotency reingest pada subset record,
  8. tolak build jika ada perubahan snapshot canonical tanpa review eksplisit,
  9. simpan artefak gagal: log importer, metadata hasil transformasi, thumbnail output, dan diff snapshot,
  10. jalankan smoke test pasca-deploy pada sejumlah record golden.

Skenario edge case yang sering terlewat

  • record tanpa title tetapi punya alternative title,
  • creator berupa organisasi, bukan orang,
  • gambar berukuran sangat besar yang memicu limit memori saat thumbnail,
  • file rusak sebagian tetapi metadata valid,
  • media URL berubah sementara external_id tetap sama,
  • record dihapus dari sumber dan perlu ditandai sebagai withdrawn, bukan dihapus permanen,
  • license statement berubah dari jelas menjadi ambigu,
  • dua sumber berbeda mengacu pada objek fisik yang sama tetapi punya kebijakan atribusi berbeda,
  • query search dengan karakter aksen atau transliterasi,
  • reprocessing derivative setelah perubahan algoritma tanpa menyentuh metadata utama.

Jika tim belum punya banyak test, mulai dari edge case yang pernah menimbulkan insiden. Itu biasanya memberi ROI tertinggi.

Tips debugging saat regresi terjadi

  • Bandingkan canonical record sebelum dan sesudah perubahan, bukan hanya output API akhir.
  • Simpan artefak per tahap pipeline: input mentah, hasil normalisasi, dokumen indeks, metadata file derivative.
  • Tambahkan reason code untuk keputusan penting seperti dedup match, rights downgrade, atau skip publish.
  • Log idempotency key dan external_id agar mudah melacak duplikasi karena retry job.
  • Pisahkan error teknis dan error kualitas data; keduanya perlu penanganan berbeda.

Tanpa artefak dan reason code, regresi data cenderung berubah menjadi investigasi manual yang lama.

Penutup

Strategi verifikasi arsip gambar publik yang efektif menggabungkan test pyramid, contract test importer, golden dataset, integrity check berbasis checksum, snapshot yang disanitasi, dan verifikasi pasca-deploy. Tujuannya bukan mengejar cakupan test tertinggi, melainkan menjaga agar ingest metadata, thumbnail generation, pencarian, deduplikasi, dan perubahan lisensi tetap benar ketika pipeline berkembang.

Jika harus memilih prioritas awal, mulai dari tiga hal: golden dataset kecil yang representatif, contract test untuk importer, dan assertion perilaku untuk search serta lisensi. Tiga komponen ini biasanya cukup untuk menangkap sebagian besar regresi data sebelum sampai ke pengguna.