channel-availability.tsfeat(inbox,two-factor,marketing): channel filter on query tabs, 2FA policy, host routing Three in-flight threads plus supporting docs, committed together. - inbox: the channel badge no longer goes empty on a Gmail-query tab — participatingChannels stops dropping chat channels when the tab rule is mailOnly, so an explicit single-channel badge asks the sources it names. - two-factor: policy module with its own tests, wired through session verification and auth, with the env and runtime-contract keys it needs. - marketing: host routing for the signed-out root, with a redirect test. - docs: inbox channel-filter bug writeup, daily agenda templates, open-tracking v2 notes, and the 2026-08-30 customer feedback audit. Co-Authored-By: Claude Opus 5 (1M context) <<email>>Sep 1, 2026, 11:53 AMhotkey-targets.tsfix(unibox): a chat id the feed forgot still isn't a Gmail thread `splitHotkeyTargets` decided what a selection id was by asking the loaded feed, and read a lookup MISS as "email". But selection and hover state outlive a feed replacement, so a miss is an ordinary event — and on one, a `li:`/`wa:`/`slack:` id went to the Gmail driver, which is precisely the modify-a-thread-that-does-not-exist this module exists to prevent. The prefix is structural (`services/inbox/feed-core.ts` mints it) and an email row's id is a bare Gmail thread id, which is hex and cannot hold a colon — so the prefix answers the question without the feed. An id that is a chat but resolves to nothing is now dropped from both halves: there is no row to act on, and no driver that could act on it. Co-Authored-By: Claude Opus 5 (1M context) <<email>>Sep 7, 2026, 4:40 PM