From a048ea1c940840b85d6ab6d704f72e02566d120a Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Sun, 28 Jun 2026 09:54:18 -0500 Subject: [PATCH] refactor(car): drop dead FuzzyNodeNameResolver duplicate (#5994) Co-authored-by: Claude Opus 4.8 --- .../feature/car/util/FuzzyNodeNameResolver.kt | 73 ----------------- .../car/util/FuzzyNodeNameResolverTest.kt | 78 ------------------- 2 files changed, 151 deletions(-) delete mode 100644 feature/car/src/main/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolver.kt delete mode 100644 feature/car/src/test/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolverTest.kt diff --git a/feature/car/src/main/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolver.kt b/feature/car/src/main/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolver.kt deleted file mode 100644 index 1018a3787..000000000 --- a/feature/car/src/main/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolver.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2026 Meshtastic LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.meshtastic.feature.car.util - -import org.koin.core.annotation.Factory - -/** - * Resolves voice-spoken node names to actual node numbers using fuzzy matching. - * - * TODO: Consolidate with FuzzyNameResolver from core/data when AppFunctions branch merges. - */ -@Factory -class FuzzyNodeNameResolver { - - data class ResolvedNode(val nodeNum: Int, val name: String, val confidence: Float) - - fun resolve(spokenName: String, nodes: List>): ResolvedNode? { - if (spokenName.isBlank() || nodes.isEmpty()) return null - - val normalizedInput = spokenName.lowercase().trim() - - return nodes - .map { (nodeNum, name) -> - val normalizedName = name.lowercase().trim() - val score = lcsScore(normalizedInput, normalizedName) - ResolvedNode(nodeNum, name, score) - } - .filter { it.confidence >= MIN_CONFIDENCE } - .maxByOrNull { it.confidence } - } - - private fun lcsScore(a: String, b: String): Float { - if (a.isEmpty() || b.isEmpty()) return 0f - val maxLen = maxOf(a.length, b.length) - val lcsLen = lcsLength(a, b) - return lcsLen.toFloat() / maxLen.toFloat() - } - - private fun lcsLength(a: String, b: String): Int { - val m = a.length - val n = b.length - val dp = Array(m + 1) { IntArray(n + 1) } - for (i in 1..m) { - for (j in 1..n) { - dp[i][j] = - if (a[i - 1] == b[j - 1]) { - dp[i - 1][j - 1] + 1 - } else { - maxOf(dp[i - 1][j], dp[i][j - 1]) - } - } - } - return dp[m][n] - } - - companion object { - private const val MIN_CONFIDENCE = 0.6f - } -} diff --git a/feature/car/src/test/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolverTest.kt b/feature/car/src/test/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolverTest.kt deleted file mode 100644 index 6594ec0a0..000000000 --- a/feature/car/src/test/kotlin/org/meshtastic/feature/car/util/FuzzyNodeNameResolverTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2026 Meshtastic LLC - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.meshtastic.feature.car.util - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue - -class FuzzyNodeNameResolverTest { - - private val resolver = FuzzyNodeNameResolver() - - private val testNodes = - listOf(1 to "Alice Base Station", 2 to "Bob Mobile", 3 to "Charlie Repeater", 4 to "Delta Gateway") - - @Test - fun `resolve returns exact match with high confidence`() { - val result = resolver.resolve("Alice Base Station", testNodes) - assertNotNull(result) - assertEquals(1, result.nodeNum) - assertEquals(1f, result.confidence) - } - - @Test - fun `resolve handles case-insensitive matching`() { - val result = resolver.resolve("alice base station", testNodes) - assertNotNull(result) - assertEquals(1, result.nodeNum) - } - - @Test - fun `resolve returns partial match with sufficient confidence`() { - val result = resolver.resolve("Alice Base Staton", testNodes) - assertNotNull(result) - assertEquals(1, result.nodeNum) - assertTrue(result.confidence >= 0.6f) - } - - @Test - fun `resolve returns null for blank input`() { - assertNull(resolver.resolve("", testNodes)) - assertNull(resolver.resolve(" ", testNodes)) - } - - @Test - fun `resolve returns null for empty node list`() { - assertNull(resolver.resolve("Alice", emptyList())) - } - - @Test - fun `resolve returns null for low-confidence match`() { - assertNull(resolver.resolve("zzz", testNodes)) - } - - @Test - fun `resolve picks best match among similar names`() { - val nodes = listOf(1 to "Charlie Alpha", 2 to "Charlie Bravo") - val result = resolver.resolve("Charlie Bravo", nodes) - assertNotNull(result) - assertEquals(2, result.nodeNum) - } -}