Skip to content

Commit 4880d05

Browse files
committed
test(performance): gate screener verdict latency
1 parent 8190518 commit 4880d05

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ All notable changes to CallShield will be documented in this file.
153153
- Release artifacts now carry an exact CycloneDX SBOM, in-toto/SLSA provenance
154154
record, and SHA-256 sidecar bound to the release-runtime lockfile; version tags
155155
also receive a GitHub OIDC build-provenance attestation.
156+
- The screener hot path now has an executable 50 ms p99 JVM benchmark covering
157+
the same verdict call used by the detection pipeline.
156158

157159
## v1.7.35 — 2026-08-10
158160

‎app/src/test/java/com/sysadmindoc/callshield/data/HotPathBenchmarkTest.kt‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,36 @@ class HotPathBenchmarkTest {
112112
)
113113
}
114114

115+
@Test
116+
fun spamScreener_verdict_p99_stays_under_50ms() {
117+
val numbers =
118+
listOf(
119+
"+12125551234",
120+
"+18005551234",
121+
"+19005551234",
122+
"+15555555555",
123+
"+13105550000",
124+
"+16465551111",
125+
"+17185559999",
126+
"+14155551234",
127+
)
128+
repeat(200) { SpamMLScorer.verdict(numbers[it % numbers.size]) }
129+
130+
val elapsedNanos =
131+
LongArray(1_000) { index ->
132+
val start = System.nanoTime()
133+
SpamMLScorer.verdict(numbers[index % numbers.size])
134+
System.nanoTime() - start
135+
}.sorted()
136+
val p99 = elapsedNanos[(elapsedNanos.size * 99 / 100).coerceAtMost(elapsedNanos.lastIndex)]
137+
val ceilingNanos = (50_000_000.0 * headroom).toLong()
138+
139+
assertTrue(
140+
"Spam screener verdict p99 took ${p99 / 1_000_000.0}ms, ceiling ${ceilingNanos / 1_000_000.0}ms",
141+
p99 < ceilingNanos,
142+
)
143+
}
144+
115145
@Test
116146
fun spamHeuristics_pure_checks_1k_iterations_under_ceiling() {
117147
// Only hit the context-free heuristics so the test stays in pure JVM.

0 commit comments

Comments
 (0)