Part of #5.
The setup UI invites a repair that cannot work, on exactly the Macs that need it.
What is there today
classify() treats a text from me as a command only when the chat identifier is in own
(app/Uplink/filter.ts#L43). That is correct and deliberate: the comment at
app/Uplink/filter.ts#L16 explains that in a chat with someone else, "from me" is me talking to them.
own comes solely from chat.db: ownHandles() selects DISTINCT destination_caller_id and account
over the message table (app/Uplink/messages-db.ts#L141). On a Mac whose Messages history is empty,
or whose rows carry empty destination_caller_id and account as SMS-relayed rows do, own stays
empty.
refreshHandles then sets allowed from config.allowed when it is non-empty
(app/Uplink/uplink.ts#L202), so typing your number into the popover does populate allowed. But it
does not populate own, and a self-text is only a command when the identifier is in own. So the
text is classified outgoing message (app/Uplink/filter.ts#L47) and ignored.
Meanwhile the popover says exactly the wrong thing: "No handles yet. Sign in to Messages, or add your
number" (app/Uplink/desktop-agent.ts#L258).
Proposal
- When a handle is configured explicitly and is one the person says is theirs, treat it as an own handle. The intent of typing your own number into "who can text it" is unambiguous.
- Keep the security property intact. The rule that protects users is that a chat with somebody else
never accepts "from me" as a command. Seeding
ownfrom an explicitly configured handle does not weaken that: the person configured it at the Mac, which is the same trust level as every other setting. - Say what is happening while
ownis empty. "Send yourself one text so Uplink can learn your handle" is a real instruction; the current text sends people to Messages they are already signed into.
Requirements
- Do not widen
ownfrom anything chat.db says about other people. Only from configuration the person entered, or from the account columns as today. - The filter's fail-closed discipline stays. This adds one documented source of own handles; it does not turn any check into a denylist.
refreshHandlesre-reads every poll whileallowedis empty (app/Uplink/uplink.ts#L193). Keep that, because the first text is what reveals the handles on a fresh Mac.- Add a test.
tests/unit/uplink/has the chat.db-shaped fixture to do it with.
Acceptance
- On a Mac with an empty Messages history, typing your own number and texting yourself works.
- A text from a third party in a one-to-one chat is still refused unless that handle is allowed.
- A test covers the empty-
owncase explicitly.