Repository navigation
T-014/T-016: the app can finally see a real device — and stops lying about it - #4
Merged
Merged
Conversation
HARDWARE-VERIFIED. The app now sees a real KitchenSync Touch.
The bug: KitchenSyncDiscovery filtered on hasPrefix("kitchensync-"). A real
Touch advertises as `kstouch-dfd0`. It wasn't rendered wrong or shown offline —
it was INVISIBLE. The prefix heuristic failed on the first real hardware this app
ever met, exactly as its own doc comment predicted.
DeviceMatch is a pure function over (serviceName, txt), tested without standing
up Bonjour. The NWBrowser glue stays dumb and only extracts the two inputs.
TXT is the truth; the hostname is a guess. When a TXT record is present, identity
is a FACT and the hostname is not consulted AT ALL — including when it would have
passed. That's what finally kills the other half of the heuristic's failure: a
stranger's box at a venue named `kitchensync-whatever` currently gets adopted
straight into the fleet, and no hostname rule can prevent it.
When TXT is ABSENT we fall back to the hostname, because no unit in the field
publishes one yet (link-devices ESP-031). Matching on TXT alone would make every
existing device vanish — a worse bug than the one being fixed.
Verified on the simulator against the live LAN: KSTOUCH-DFD0.LOCAL now appears
under DISCOVERED. 91 tests, 0 failures.
Known, and next: the device shows as UNREACHABLE despite answering HTTP 200,
because KsStatus throws on decode (Touch is missing 11 required keys — see
link-devices ESP-029). The app is conflating "I cannot understand this device"
with "this device is gone". Different failures, different fixes. Filed separately.
HARDWARE-FOUND. With discovery fixed (T-014), the app finally saw a real KitchenSync Touch — and immediately labelled it UNREACHABLE, while curl got HTTP 200 from that same host. The device was answering perfectly. The app just couldn't understand what it said. refreshStatus() did `try? await client.fetchStatus()`, so a DECODE failure and a TRANSPORT failure collapsed into the same nil. Three of those and T-010's reachability counter declared a live, healthy device dead. Telling a user their device is unreachable sends them off to debug a network that is working fine. The real problem is a protocol mismatch, and the real fix is a firmware update. The label has to point at that. This is the same mistake T-009 already fixed one endpoint over: a /config.json 404 is not a dead network. Here it is /status. - DeviceListViewModel.Reachability gains .unsupported, and it OUTRANKS the miss counter: a device that is plainly THERE must never be reported as gone, however long we have failed to read it. An undecodable poll is not a miss and does not advance the counter. - DeviceDetailViewModel gains StatusAvailability for the same split. - The list says UNSUPPORTED FW / CAN'T READ instead of UNREACHABLE / NO SIGNAL. "NO SIGNAL" was itself a lie: the device is signalling perfectly, in a dialect we cannot read. - T-010's behaviour is preserved and pinned: a device that genuinely stops answering is still UNREACHABLE. The test fixture is the REAL Touch /status response, captured verbatim from kstouch-dfd0. It is missing 11 keys KsStatus requires (min first, then usb, tx, fw, follow_*, launch, playing, link_owns). That fixture goes GREEN the day link-devices ESP-029 ships and the Touch shares ks_status.c. Keep it. 94 tests, 0 failures. Verified against the real device on the LAN.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The first two bugs found by real hardware. Both were invisible from source; both needed a KitchenSync Touch on the LAN to surface.
T-014 — the app could not SEE the device
KitchenSyncDiscoveryfiltered onhasPrefix("kitchensync-"). A real Touch advertises askstouch-dfd0. It wasn't rendered wrong or shown offline — it was invisible. The prefix heuristic failed on the first real hardware this app ever met, exactly as its own doc comment predicted it would.DeviceMatchis now a pure function over(serviceName, txt), tested without standing up Bonjour. TheNWBrowserglue stays dumb and just extracts the two inputs.TXT is the truth; the hostname is a guess. When a TXT record is present, identity is a fact and the hostname isn't consulted at all — including when it would have passed. That kills the heuristic's other failure mode: a stranger's box at a venue named
kitchensync-whatevercurrently gets adopted straight into the fleet, and no hostname rule can prevent it.When TXT is absent we fall back to the hostname, because no unit in the field publishes one yet (ESP-031). Matching on TXT alone would make every existing device vanish — a worse bug than the one being fixed.
T-016 — and then the app called that live device "unreachable"
With discovery fixed, the Touch appeared… and was immediately labelled UNREACHABLE, while
curlgot HTTP 200 from that exact host.refreshStatus()didtry? await client.fetchStatus(), collapsing a decode failure and a transport failure into the samenil. Three of those and T-010's reachability counter declared a live, healthy device dead.Telling a user their device is unreachable sends them to debug a network that is working perfectly. The real problem is a protocol mismatch and the real fix is a firmware update — the label has to point at that. This is the identical mistake T-009 already fixed one endpoint over (a
/config.json404 is not a dead network); here it's/status..unsupportedoutranks the miss counter: a device that is plainly there must never be reported as gone, however long we've failed to read it. An undecodable poll is not a miss.The fixture is the real device
The test fixture is
kstouch-dfd0's actual/statusresponse, captured verbatim. It's missing 11 keysKsStatusrequires (minfirst, thenusb,tx,fw,follow_*,launch,playing,link_owns).That fixture goes green the day ESP-029 ships and the Touch shares
ks_status.c. It's a regression test with an expiry date, and it's worth keeping.94 tests, 0 failures. Verified on the simulator against the live LAN and a real device.
https://claude.ai/code/session_01F7YsQgso3KNpeXbP5vNVj6