The web console shows exactly what the host was told, and the host was told
"This device" by every Apple client — so the outstanding-pairings view and the
approve dialog listed identical rows for an iPad, an Apple TV and a Mac.
The name rides `Hello::name`, which embedders fill from `client::device_name()`.
That resolves `COMPUTERNAME` (Windows-only) then `HOSTNAME` (a shell variable
never exported into a launchd-started process), and its last resort was the
literal "This device". No Apple GUI app has either variable, and the C ABI had
no device-name parameter for one to pass a better answer through, so every
Apple device fell through to the placeholder. Linux (/etc/hostname) and Windows
were unaffected; Android sent `Build.MODEL`, which names the product rather than
the unit — two of the same tablet were still indistinguishable.
- core: `punktfunk_connect_ex10` = `ex9` + `device_name` (C ABI v21, no wire
change — `ex9` keeps its signature and passes a null name for the old
default). Truncated to `HELLO_NAME_MAX` on a character boundary, since
slicing a multi-byte name mid-scalar panics.
- core: `device_name()` falls back to `gethostname()` before the placeholder,
so an embedder that passes nothing still gets a real name.
- apple: `DeviceName.current` (`Host.localizedName` / `UIDevice.current.name`,
falling back to the hostname when 16+ answers with the bare model) is sent on
connect, and the two pairing sheets plus the ceremony now read that one source
instead of three separate literals.
- android: `Settings.Global.DEVICE_NAME` — the name the user typed in Settings —
ahead of `Build.MODEL`. The "approve this device" prompt quotes the same
string the connect knocks with, so it can't send the user looking for a row
the console does not show.
- web: the approve dialog names the device and its fingerprint. A pre-filled
field is editable text, not a statement of which knock is being approved.