An external audit of quarkus-work-ledger came back with three findings. I worked through them with Claude.
buildDecisionContext was building a JSON snapshot using String.format:
return String.format(
"{\"status\":\"%s\",\"priority\":\"%s\",\"assigneeId\":%s,\"expiresAt\":%s}",
wi.status, wi.priority,
wi.assigneeId != null ? "\"" + wi.assigneeId + "\"" : "null",
wi.expiresAt != null ? "\"" + wi.expiresAt + "\"" : "null");
A quote or backslash in any actor ID silently produces malformed JSON. It passes every test and breaks quietly in production when someone uses a non-trivial identifier. We replaced it with Jackson ObjectNode, which is already on the classpath via quarkus-rest-jackson and handles escaping correctly.
The second finding: eventSuffix() can return null, and the downstream EVENT_META.get(null) — where EVENT_META uses Map.ofEntries() — “returns null, and the subsequent array index throws NPE.”
Except Map.ofEntries().get(null) doesn’t return null. It throws NullPointerException directly. Map.of() and Map.ofEntries() reject null in all operations including reads — unlike HashMap, where get(null) silently returns null. The auditor had the same HashMap mental model as most Java developers.
The fix was straightforward — guard against null before calling get(). What’s worth noting is that the audit’s own description of the bug was wrong. That’s how deep the HashMap assumption runs.
TrustScoreComputerTest had 8 failing expectations. Tests were asserting score ≈ 1.0 for actors with clean decision records and no attestations. The actual result was 0.5.
The algorithm uses a Bayesian Beta model with prior Beta(1, 1). Score = α/(α+β). With no attestations: α=1.0, β=1.0 → score=0.5. Unattested decisions contribute nothing — only attestations move the needle. “No evidence of wrongdoing” and “trustworthy” are not the same thing to a Bayesian model.
The same team who wrote the algorithm had assumed the intuitive model: clean history implies high trust. The math says: no evidence implies maximum uncertainty.
Two of those tests also had a subtler problem. The recency fixture set decision.occurredAt but left attestation.occurredAt null. The decay function uses the attestation timestamp. With null occurredAt, every attestation defaults to age=0 and gets identical weight — the test was asserting recency weighting without actually exercising it.
We fixed all 8. 76 tests pass in quarkus-work-ledger.