From a12962fd778db4668bd0b349318462e763f2dcf9 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Wed, 15 Jul 2026 02:16:44 -0400 Subject: [PATCH] =?UTF-8?q?feat(discovery):=20KitchenSync=20only=20?= =?UTF-8?q?=E2=80=94=20drop=20X32Link=20from=20the=20matcher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X32Link is a separate product with its own app; it doesn't belong in the KitchenSync app. Removed `x32link` from the hostname prefixes, and the TXT path already matches only `dev=kitchensync` — so with the firmware now publishing `dev=x32link`, X32Link is excluded by both paths. The P4 and its Touch / Super Mini versions stay. Briefly included in ESP-035 before the product line was clarified. Claude-Session: https://claude.ai/code/session_01F7YsQgso3KNpeXbP5vNVj6 --- .../KitchenSyncApp/Discovery/DeviceMatch.swift | 14 +++++++------- Tests/KitchenSyncAppTests/DeviceMatchTests.swift | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/KitchenSyncApp/Discovery/DeviceMatch.swift b/Sources/KitchenSyncApp/Discovery/DeviceMatch.swift index d96e551..c90785e 100644 --- a/Sources/KitchenSyncApp/Discovery/DeviceMatch.swift +++ b/Sources/KitchenSyncApp/Discovery/DeviceMatch.swift @@ -31,17 +31,17 @@ enum DeviceMatch { /// /// The firmware advertises generic `_http._tcp` with no TXT record, so the hostname is all a /// client has. The hostname is `-`: `kitchensync-a4f2` on the - /// P4, `kstouch-dfd0` on the Touch, `x32link-7a1c` on the headless (ESP-035). Missing - /// `kstouch` is what made a real device invisible once already. + /// P4, `kstouch-dfd0` on the Touch. Missing `kstouch` made a real device invisible once. private static func matchesKnownHostname(_ name: String) -> Bool { let lower = name.lowercased() // a Bonjour instance name's case is not meaningful — // the P4 advertises "KitchenSync", the Touch "kstouch-…" return knownHostPrefixes.contains { lower.hasPrefix($0) } } - /// `x32link` joined this list in ESP-035 — but adding it here was the SMALL half. That - /// unit had no mDNS whatsoever: it never advertised, so no matcher could have found it. - /// The user saw it exactly that way — "I see kstouch, not the headless" — while the box - /// sat there powered, on the network, and following the session. - private static let knownHostPrefixes = ["kitchensync", "kstouch", "x32link"] + /// KitchenSync ONLY — the P4 and its Touch / Super Mini versions. X32Link is a SEPARATE + /// product (it happens to speak Link too) with its own app, so it is deliberately NOT + /// here, and the firmware publishes `dev=x32link` so the TXT path excludes it as well. + /// `x32link` was briefly in this list (ESP-035); removed once it became clear this app is + /// KitchenSync's, not the fleet's. + private static let knownHostPrefixes = ["kitchensync", "kstouch"] } diff --git a/Tests/KitchenSyncAppTests/DeviceMatchTests.swift b/Tests/KitchenSyncAppTests/DeviceMatchTests.swift index f8c9122..eee753f 100644 --- a/Tests/KitchenSyncAppTests/DeviceMatchTests.swift +++ b/Tests/KitchenSyncAppTests/DeviceMatchTests.swift @@ -58,14 +58,14 @@ final class DeviceMatchTests: XCTestCase { "a TXT record that says it ISN'T ours must beat a hostname that says it is") } - /// ESP-035: the headless X32Link. It was the last unit in the fleet with NO mDNS at - /// all -- it never advertised, so it could not be found no matter what this matcher - /// did. Now it announces `x32link-`, and the prefix list has to know the name. - /// - /// The user hit this exactly: "I see kstouch. not the headless." The device was - /// powered, on the network, and following the Link session. - func test_the_headless_x32link_is_one_of_ours() { - XCTAssertTrue(DeviceMatch.isKitchenSync(serviceName: "x32link-7a1c", txt: nil)) + /// X32Link is a SEPARATE product with its own app — this KitchenSync app must NOT show + /// it, by hostname OR by its (now `dev=x32link`) TXT. It was briefly included (ESP-035) + /// before the product line was clarified. + func test_the_x32link_is_not_shown_in_the_kitchensync_app() { + XCTAssertFalse(DeviceMatch.isKitchenSync(serviceName: "x32link-7a1c", txt: nil)) + XCTAssertFalse(DeviceMatch.isKitchenSync(serviceName: "X32Link", txt: nil)) + XCTAssertFalse(DeviceMatch.isKitchenSync(serviceName: "x32link-6160", + txt: ["dev": "x32link", "model": "x32link"])) } /// The prefix is still a HEURISTIC, and it must not swallow the whole network. A