Selama 60 tahun, mesin aturan berdiri di atas premis yang sama. Premis bahwa objek validasi adalah “fakta (fact)”.
Drools memasukkan objek Java sebagai “fact” ke working memory. Rego memperlakukan input sebagai data yang sudah benar. JSON Schema menganggap struktur dokumen sudah diberikan. Semuanya asumsi yang sama — data yang masuk adalah fakta.
Tapi apa sebenarnya alasan keberadaan mesin aturan? Memvalidasi apakah data memenuhi aturan. Menyebut objek yang perlu divalidasi sebagai “sesuatu yang sudah benar” adalah kontradiksi.
Bukan Fakta, Melainkan Klaim
Objek validasi bukan fact, melainkan claim (klaim). Sebuah pernyataan yang bisa benar atau salah. Keabsahannya harus dinilai oleh aturan.
JWT sudah mengikuti prinsip ini. sub, exp, iss disebut bukan “facts” melainkan “claims”. Itu adalah klaim dari penerbit token. Baru bisa dipercaya setelah memverifikasi tanda tangan, memeriksa kedaluwarsa, dan mencocokkan issuer.
Struktur ini sudah ditetapkan pada tahun 1958.
Model Argumentasi Toulmin
Stephen Toulmin pada tahun 1958 menganalisis struktur argumentasi menjadi 6 elemen:
- Claim (Klaim): Objek penilaian. Sesuatu yang harus diverifikasi benar atau salah.
- Ground (Dasar): Data bukti yang digunakan untuk penilaian.
- Warrant (Jaminan): Aturan yang menilai bahwa dasar mendukung klaim.
- Backing (Dukungan): Justifikasi mengapa aturan tersebut valid.
- Qualifier (Kualifikasi): Tingkat keyakinan penilaian.
- Rebuttal (Sanggahan): Kondisi pengecualian di mana klaim tidak berlaku.
Logika formal mengatakan “jika premis benar, maka kesimpulan juga benar”. Toulmin berbeda. “Klaim didukung oleh dasar dan aturan, tetapi bisa dibatalkan jika ada kondisi pengecualian.” Semua argumentasi dapat disanggah.
Selama 60 tahun, mesin aturan berdiri di sisi logika formal. Input adalah fact, hasilnya allow/deny, pengecualian ditangani mekanisme terpisah. Toulmin berada di sisi sebaliknya. Input adalah claim, hasilnya derajat (degree), pengecualian sudah tertanam.
Masalahnya — buku Toulmin ditempatkan di rak filsafat. Tidak terlihat di rak mesin aturan. Missing link selama 60 tahun.
Maka Dibuatlah Mesin Aturan
toulmin adalah implementasi model argumentasi Toulmin sebagai mesin aturan Go.
Kebutuhan Berevolusi
Mari lihat bagaimana if-else dan toulmin merespons evolusi yang sama.
// Senin: "Hanya pengguna terautentikasi yang boleh akses, blokir IP diterapkan, jaringan internal dikecualikan dari blokir"
g := toulmin.NewGraph("api:access")
auth := g.Warrant(isAuthenticated, nil, 1.0)
blocked := g.Rebuttal(isIPBlocked, nil, 1.0)
exempt := g.Defeater(isInternalIP, nil, 1.0)
g.Defeat(blocked, auth)
g.Defeat(exempt, blocked)
// Selasa: "Tambah Rate limiting"
limited := g.Rebuttal(isRateLimited, nil, 1.0)
g.Defeat(limited, auth)
// Rabu: "Pengguna premium dikecualikan dari Rate limit"
premium := g.Defeater(isPremiumUser, nil, 1.0)
g.Defeat(premium, limited)
// Kamis: "Saat penanganan insiden, premium pun dibatasi"
incident := g.Rebuttal(isIncidentMode, nil, 1.0)
g.Defeat(incident, premium)
Setiap hari tambah 2 baris, tidak ada perubahan kode yang sudah ada. Evolusi yang sama dengan if-else:
// Senin
if user != nil {
if blockedIPs[ip] {
if strings.HasPrefix(ip, "10.") {
allow = true
}
} else {
allow = true
}
}
// Kamis — 4 level nesting, struktur tidak bisa dipahami
if user != nil {
if blockedIPs[ip] {
if strings.HasPrefix(ip, "10.") {
allow = true
}
} else if isRateLimited(ip) {
if isPremium(user) {
if !incidentMode {
allow = true
}
}
} else {
allow = true
}
}
toulmin: 2 baris per kebutuhan, struktur tidak berubah. if-else: Setiap kali harus membongkar seluruh struktur.
Aturan Adalah Fungsi Go
func(claim any, ground any, backing any) (bool, any)
ground= bahan penilaian yang berubah setiap request (pengguna, IP, konteks)backing= kriteria penilaian yang ditetapkan saat deklarasi graph (threshold, nama role, konfigurasi)- Return =
(hasil penilaian, bukti). Bukti bertipe bebas sesuai domain.
func CheckOneFileOneFunc(claim, ground, backing any) (bool, any) {
g := ground.(*FileGround)
if len(g.Funcs) > 1 {
return true, &Evidence{Got: len(g.Funcs), Expected: 1}
}
return false, nil
}
Tidak perlu belajar bahasa baru seperti Rego. Cukup tulis fungsi Go.
backing — Fungsi Sama, Kriteria Penilaian Berbeda
backing meneruskan kriteria penilaian aturan sebagai nilai runtime. Mendaftarkan fungsi yang sama dengan backing berbeda menjadi aturan terpisah:
g := toulmin.NewGraph("access")
admin := g.Warrant(isInRole, "admin", 1.0)
editor := g.Warrant(isInRole, "editor", 0.8)
g := toulmin.NewGraph("line-limit")
strict := g.Warrant(CheckLineCount, &LineLimit{Max: 100}, 0.7)
relaxed := g.Warrant(CheckLineCount, &LineLimit{Max: 200}, 0.5)
g.Defeat(relaxed, strict)
Jika backing nil, artinya aturan tidak memerlukan kriteria penilaian.
Pengecualian Dideklarasikan sebagai Graph
Deklarasikan hubungan antar aturan dengan Graph Builder API, mesin menangani sisanya. Fungsi adalah identifier. Tidak perlu nama string.
g := toulmin.NewGraph("filefunc")
w := g.Warrant(CheckOneFileOneFunc, nil, 1.0)
d := g.Defeater(TestFileException, nil, 1.0)
g.Defeat(d, w)
results, _ := g.Evaluate(claim, ground)
Fungsi yang sama dapat digunakan kembali di graph berbeda dengan hubungan defeat berbeda:
strictGraph := toulmin.NewGraph("strict")
strictGraph.Warrant(CheckOneFileOneFunc, nil, 1.0)
// Tanpa pengecualian — file test pun tidak diizinkan
lenientGraph := toulmin.NewGraph("lenient")
w := lenientGraph.Warrant(CheckOneFileOneFunc, nil, 1.0)
r1 := lenientGraph.Rebuttal(TestFileException, nil, 1.0)
r2 := lenientGraph.Rebuttal(GeneratedFileException, nil, 0.8)
lenientGraph.Defeat(r1, w)
lenientGraph.Defeat(r2, w)
// File test + file generated keduanya pengecualian
Melacak Dasar Penilaian
EvaluateTrace melacak tidak hanya verdict tetapi juga aturan mana yang aktif dan aturan mana yang mengalahkan aturan lainnya:
traced := g.EvaluateTrace(claim, ground)
// traced[0].Verdict: +0.6
// traced[0].Trace: [
// {Name: "CheckOneFileOneFunc", Role: "warrant", Activated: true, Qualifier: 1.0},
// {Name: "TestFileException", Role: "rebuttal", Activated: true, Qualifier: 1.0},
// ]
Ketika ada puluhan aturan, “mengapa verdict ini muncul” dapat dibaca oleh manusia.
Penilaian Dihitung dengan Satu Rumus
Menerapkan h-Categoriser dari Amgoud (2013):
raw = w / (1 + Σ raw(attackers))
verdict = 2 × raw - 1
+1.0— pelanggaran terkonfirmasi0.0— tidak dapat dinilai-1.0— sanggahan terkonfirmasi
Ketika aturan aktif, ia menjadi warrant. Ketika pengecualian juga aktif, ia menjadi attacker. Rumus menghitung kekuatan keduanya dan menghasilkan verdict. Bagaimana jika ada pengecualian dari pengecualian? Ia menjadi attacker dari attacker, memulihkan aturan asli. Prinsip Kompensasi (Compensation) — sifat yang hanya dipenuhi oleh h-Categoriser.
Aturan Memiliki Tiga Tingkat Kekuatan
Menerapkan klasifikasi Nute (1994):
| Kekuatan | Makna | Contoh |
|---|---|---|
| Strict | Tidak bisa dilumpuhkan | “Tidak bisa akses admin API tanpa autentikasi” |
| Defeasible | Bisa dilumpuhkan oleh pengecualian | “Satu fungsi per file” |
| Defeater | Tanpa klaim sendiri, hanya memblokir aturan lain | “File test adalah pengecualian” |
Aturan Strict menolak edge serangan. Defeater hanya menyerang tanpa penilaian sendiri. Ini mengekspresikan tingkat penegakan aturan secara struktural.
Apa Bedanya dengan Rego
| Rego | toulmin | |
|---|---|---|
| Penulisan aturan | Perlu belajar DSL Rego | Fungsi Go |
| Penanganan pengecualian | Pola default/else manual | Deklarasi graph defeats |
| Penilaian | allow/deny biner | Nilai kontinu [-1, +1] |
| Justifikasi aturan | # METADATA (diabaikan mesin) | backing (bagian dari struktur) |
| Kekuatan aturan | Tidak ada | strict/defeasible/defeater |
| Ukuran mesin | Puluhan ribu baris | Ratusan baris |
| Kecepatan | Interpreter (parsing->AST->evaluasi) | Pemanggilan langsung fungsi Go |
Rego itu luas — ada ekosistem integrasi Kubernetes, Terraform, Envoy. toulmin itu dalam — memiliki apa yang tidak dimiliki Rego (defeasibility, qualifier, backing).
Reposisi Qualifier
Dalam model asli Toulmin, Qualifier melekat pada Claim. “Mungkin pasien ini harus diberi penisilin” — modal qualifier yang mengekspresikan tingkat keyakinan klaim.
Mesin toulmin memindahkan Qualifier dari Claim ke setiap Rule. Dalam mesin aturan, claim hanyalah objek validasi. “File ini memiliki 3 fungsi” — itu verifikasi fakta, bukan sesuatu yang perlu tingkat keyakinan. Yang menentukan kualitas penilaian adalah tingkat keyakinan aturan:
- “Satu fungsi per file” — qualifier 1.0 (aturan pasti)
- “Disarankan di bawah 100 baris” — qualifier 0.7 (aturan fleksibel)
Qualifier setiap Rule menjadi bobot awal w(a) dari h-Categoriser, dan verdict akhir menggantikan peran yang seharusnya diemban Qualifier dalam model asli Toulmin — tingkat keyakinan penilaian.
Pembuktian: Konversi Toulmin untuk 22 Aturan filefunc
filefunc adalah alat konvensi struktur kode untuk pengembangan Go native LLM. Seluruh 22 aturan dikonversi menjadi warrant Toulmin.
Klasifikasi Kekuatan
| Strength | Jumlah | Rasio | Contoh |
|---|---|---|---|
| Strict | 15 | 68% | F1, F2, F3, F4, A1-A3, A6-A16 |
| Defeasible | 4 | 18% | Q1, Q2, Q3, C4 |
| Defeater | 3 | 14% | F5, F6, pengecualian file test |
Mayoritas strict — konvensi struktur kode pada dasarnya meminimalkan pengecualian.
Hasil Kuantitatif
| Proyek | Jumlah File (sebelum->sesudah) | Rata-rata LOC/File (sebelum->sesudah) | Penyelesaian Pelanggaran SRP | Penyelesaian Pelanggaran depth |
|---|---|---|---|---|
| filefunc | — (patuh sejak awal) | 25.1 | 0 | 0 |
| fullend | 87->1.260 | 244->25.4 | 66->0 | 148->0 |
| whyso | 12->99 | 147.8->24.4 | 12->0 | 23->0 |
fullend bertambah dari 87 file menjadi 1.260. Jumlah file meledak tetapi rata-rata LOC turun dari 244 menjadi 25.4. 66 pelanggaran SRP dan 148 pelanggaran depth semuanya menjadi 0.
Dasar Teoritis
Tidak ada teori orisinal. Semuanya penelitian yang sudah ada:
| Elemen | Karya Asli |
|---|---|
| Struktur 6 elemen | Toulmin (1958) |
| strict/defeasible/defeater | Nute (1994) |
| h-Categoriser | Amgoud & Ben-Naim (2013) |
Orisinalitasnya adalah penemuan bahwa hal-hal ini saling terhubung. Selama 60 tahun, hal-hal yang masing-masing berada di filsafat (Toulmin), logika (Nute), dan teori argumentasi (Amgoud) bertemu di satu titik — mesin aturan perangkat lunak.
Menghitung Kontrak
Alasan supremasi hukum bekerja bukan karena hakim pintar. Karena struktur memaksa penilaian. Ada aturan, pengecualian dideklarasikan, dan putusan dihasilkan berdasarkan bukti.
toulmin memindahkan struktur ini ke dalam kode.
- Warrant = pasal undang-undang
- Backing = maksud legislasi
- Strength = ketentuan wajib vs ketentuan opsional
- Rebuttal = pasal pengecualian
- Claim = perkara
- Ground = bukti
- h-Categoriser = putusan
Deklarasikan kontrak (warrant), deklarasikan pengecualian (rebuttal), masukkan bukti (ground), maka penilaian (verdict) dihitung.
Bukan manusia yang menilai. Rumus yang menghitung.
Acc(a) = w(a) / (1 + Σ Acc(attackers))
Graph Dapat Didefinisikan dengan YAML
Tanpa kode Go, deklarasikan struktur graph dengan YAML dan generate kode:
graph: filefunc
rules:
- name: CheckOneFileOneFunc
role: warrant
qualifier: 1.0
- name: TestFileException
role: rebuttal
qualifier: 1.0
defeats:
- from: TestFileException
to: CheckOneFileOneFunc
toulmin graph filefunc.yaml # graph_gen.go 생성
Cukup tulis fungsi aturan di Go. Struktur graph dideklarasikan oleh YAML.
MIT License. github.com/park-jun-woo/toulmin