Tantangan Regresi pada Autonomous Coding Agent
Coding agent berbasis LLM (seperti Claude Code, Devin, atau implementasi kustom berbasis LangGraph) kerap menyelesaikan masalah lokal namun memicu regresi pada modul lain. Fenomena ini memburuk ketika agent menghadapi hallucinated patches: kode yang secara sintaksis valid dan lulus verifikasi prompt internal, namun mematahkan edge case historis yang tidak terdokumentasi dalam konteks aktif.
Untuk mengatasinya, agent membutuhkan Memory Test Harness. Sistem ini menggabungkan basis data solusi masa lalu (recipes/fixes) dengan pipeline verifikasi deterministik sebelum agent diizinkan menjalankan perintah git commit.
Arsitektur Penyimpanan Memori: Vector Store vs Local File
Penyimpanan memori solusi masa lalu dapat diimplementasikan menggunakan dua strategi utama:
- Vector Store (ChromaDB / Qdrant): Efektif untuk repositori besar dengan ribuan solusi modular. Memetakan error stack trace dan diff deskriptif ke dalam representasi vektor numerik untuk pencarian semantik berkecepatan tinggi.
- Local File Store (Markdown / JSONL under
.agent/memory/): Pendekatan zero-dependency yang disimpan langsung di git tree. Tepat untuk proyek monorepo berukuran menengah karena langsung terlacak versi konfigurasinya bersama commit kode.
Struktur artefak memori harus menyatukan deskripsi error, diff solusi, dan suite pengujian verifikasi:
{
"id": "fix-null-pointer-auth-header",
"error_signature": "TypeError: Cannot read properties of undefined (reading 'split')",
"context_path": "src/middleware/auth.ts",
"patch_diff": "--- a/src/middleware/auth.ts\n+++ b/src/middleware/auth.ts\n@@ -12,2 +12,3 @@\n- const token = req.headers.authorization.split(' ')[1];\n+ const authHeader = req.headers.authorization;\n+ const token = authHeader ? authHeader.split(' ')[1] : null;",
"test_cases": [
"tests/unit/auth-null-header.test.ts"
]
}Implementasi Verification Workflow Sebelum Commit
Harness verifikasi bekerja sebagai gerbang terisolasi (sandbox gatekeeper). Agent tidak diperbolehkan langsung melakukan push atau commit otomatis sebelum harness memvalidasi patch terhadap riwayat pengujian masa lalu.
import subprocess
import json
from pathlib import Path
class MemoryVerificationHarness:
def __init__(self, memory_index_path: str):
self.memory_index = Path(memory_index_path)
def retrieve_relevant_tests(self, modified_file: str) -> list[str]:
if not self.memory_index.exists():
return []
with open(self.memory_index, 'r') as f:
data = json.load(f)
# Ambil daftar tes terkait file yang diubah
matched_tests = []
for entry in data.get("recipes", []):
if entry.get("context_path") == modified_file:
matched_tests.extend(entry.get("test_cases", []))
return list(set(matched_tests))
def verify_patch(self, modified_file: str) -> bool:
tests = self.retrieve_relevant_tests(modified_file)
if not tests:
# Ponytail: default ke suite pengujian standar jika tidak ada memori spesifik
cmd = ["pytest", "-q", "tests/base/"]
else:
cmd = ["pytest", "-q"] + tests
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"[HARNESS FAILURE] Regresi terdeteksi:\n{result.stdout}")
return False
print("[HARNESS SUCCESS] Seluruh tes regresi dan test harness lulus.")
return True
# Eksekusi sebelum agent finalize commit
harness = MemoryVerificationHarness(".agent/recipes.json")
is_safe = harness.verify_patch("src/middleware/auth.ts")
assert is_safe, "Patch agent ditolak: mematahkan invariant memori masa lalu."Mitigasi Flaky Test Akibat Hallucinated Patch
Agent sering memodifikasi file test suite alih-alih memperbaiki kode inti saat menghadapi kegagalan eksekusi. Terapkan batasan deterministik berikut pada test runner harness:
- File Test Read-Only: Pasang aturan pada file sandbox di mana agent hanya memiliki izin
writepada direktorisrc/dan dilarang mengubah file di dalamtests/. - Deterministik Timeout & Mock Injection: Gunakan mocking strict pada API eksternal dan batas eksekusi deterministik (misal 5000ms per test runner) untuk mencegah agent terjebak dalam infinite loop logic.
- Double-Pass Validation: Jalankan test harness pada base tree (sebelum patch) untuk memastikan test memang valid, lalu jalankan pada patched tree untuk memvalidasi fix.
Assert Deterministik untuk Edge Cases Lama
Pengujian regresi memory-driven harus bersifat black-box dan bebas dari side-effects global state. Gunakan deterministic assert tanpa random input:
import pytest
from app.parser import parse_custom_payload
def test_parser_memory_regression_issue_402():
# Memori kasus: Payload kosong menyebabkan IndexError
payload_kosong = ""
result = parse_custom_payload(payload_kosong)
assert result == {}, "Harus mengembalikan dict kosong jika payload kosong"
def test_parser_memory_regression_issue_488():
# Memori kasus: Encoding malformed tidak boleh melempar unhandled exception
malformed_payload = "\x00\xFF--invalid"
result = parse_custom_payload(malformed_payload)
assert result.get("status") == "error"
assert "encoding_failure" in result.get("error_code")Trade-offs dan Praktik Operasional
Menerapkan memory test harness menambah runtime overhead saat iterasi agent berjalan. Menjalankan seluruh riwayat pengujian untuk setiap modifikasi kecil memperpanjang siklus eksekusi agen secara signifikan.
Gunakan filtering relevansi: jalankan hanya pengujian yang beririsan dengan file path atau dependensi AST dari kode yang diubah oleh agent. Lakukan eksekusi test suite lengkap (full integration test) hanya satu kali sebelum branching commit dinaikkan menjadi pull request final.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!