Repository navigation
Hide Spam and unknown-sender chats via bridge.conf - #49
Conversation
iPhone Messages files Spam as chat.is_filtered=2 and Filter Unknown Senders as 1; the phone badge ignores both. Blip counted them, so the bar disagreed with the phone. hide_spam=on / hide_unknown=on drop those chats at the Mac query (default off). Mute list still covers inbox spam.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
hide_spam drops those rows in SQL, so catch-up can never see the old unreadOldest timestamp. The capped path then copied the prior ledger back, pinning every poll at 8192 rows and keeping the bar badge. Restore only chats still listed by imsg chats.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e5c7eaa42
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const listed = (deep || fetched.capped) ? dropMutedChats(fetchChats(), mute, muted) : null; | ||
| if (fetched.capped) { | ||
| // The window stopped short of the oldest outstanding unread: a chat with | ||
| // NO row in the window keeps its ledger entry instead of being reset to | ||
| // zero by a rebuild that never saw it (Astra B#3). | ||
| const inWindow = new Set(msgs.map(chatKey)); | ||
| for (const [c, n] of Object.entries(state.unreadCounts)) { | ||
| if (n > 0 && !inWindow.has(c) && !(c in exactCounts)) { | ||
| exactCounts[c] = n; | ||
| if (state.unreadOldest[c]) exactOldest[c] = state.unreadOldest[c]!; | ||
| } | ||
| } | ||
| const kept = keepCappedUnread( | ||
| exactCounts, exactOldest, | ||
| state.unreadCounts, state.unreadOldest, | ||
| inWindow, visibleLedgerChats(msgs, listed), |
There was a problem hiding this comment.
Preserve unread entries when the chat listing is incomplete
When catch-up reaches the 8,192-row cap, fetchChats() can return null after a transient second bridge failure or omit an older unread conversation because CHAT_LIST_LIMIT is only 300. In either case visibleLedgerChats treats the absent chat as hidden, so keepCappedUnread permanently removes its prior unread count; the next poll then advances the cutoff and cannot recover those older unread messages. Absence from this fallible, bounded listing cannot distinguish a filtered chat from an unlisted one, so preserve the ledger unless the bridge explicitly identifies the chat as hidden.
Useful? React with 👍 / 👎.
| Needs a `blip-setup` re-run (or a copy of `bridge/mac/imsg` to the Mac) | ||
| so `--hide-spam` / `--hide-unknown` exist on the far side. |
There was a problem hiding this comment.
Require updating the Linux shim in the manual install path
The documented alternative does not enable this feature for an existing installation: copying only bridge/mac/imsg adds support for the flags, but the old Linux shim never reads hide_spam or hide_unknown and therefore never supplies those flags. Users following this parenthetical will see no filtering; instruct them to update both bridge/mac/imsg and bridge/linux/blip-shim, as the commit message already does.
Useful? React with 👍 / 👎.
…ad as a failure PR #43 merged fine but its workflow run is recorded as failed, because the approval expired before any job started. Zero jobs, no logs, and an annotation that looks exactly like a test regression to whoever opened the PR. Verified rather than assumed. The repo's policy is `{"approval_policy":"first_time_contributors"}`, the cited run (34064507217, event=pull_request, head duplicate-cards-and-instant-send) is conclusion=failure, and this is not historical: PR #49 has two runs sitting at conclusion=action_required right now, which is why it shows "no checks reported" while #45 through #48 all show a passing test job. CONTRIBUTING now tells contributors what an expired approval looks like and that it is not their code, and tells maintainers to approve before merging so a merged PR carries a real green tick. Deliberately NOT done, both need the owner's decision: - Changing the approval policy. Relaxing it means untrusted fork code runs in CI on push, which is a security trade-off, not a docs fix. - Approving the two runs waiting on #49. Same reason: it executes that fork's workflow. No runtime change, which matches the reporter's own framing. LR-T: issue-44, ci, fork-pr-approval, github-actions LR-D: blip, ci, docs LR-K: an-expired-approval-is-not-a-test-failure Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MjLJVjERSup2CMwVehKja7
…nst the wrong bytes WHAT: Fred — "when someone sends me more than one picture in a single text, the photos dont come thru," with a real example. Diagnosed on that message (two HEICs from one send): chat.db says 5.07 MB 4.27 MB (the HEIC source) sips --jpeg gives 7.80 MB 6.33 MB (the converted transfer) auto-fetch cap 5.00 MB Two independent rejections, one at each end. autoFetchImages() gated on the SOURCE size, so the 5.07 MB photo was never even requested; fetch.ts applied the same 5 MB to the CONVERTED bytes, so the 4.27 MB one was requested and then refused. Neither ever appeared. Nothing to do with there being two of them — a single full-resolution iPhone photo fails identically; batches just make it obvious, because that is when people send full-size frames. FIX: an auto-fetch is for a bubble that draws at ~800 px, so ask the Mac for a display-sized frame instead of a full one. `imsg attachment --max-dim N` resamples with sips (-Z, long edge, never upscales, quality 80). fetch.ts requests it for EVERY image, not just HEIC — a 12 MP PNG shipped raw is just as slow. The same two photos now arrive at 0.86 MB and 0.73 MB. Previews get their own cache slot, `<id>-prev-<name>.jpg`: always JPEG, so always named .jpg (xdg-open dispatches on extension — war room nixfred#49), and it cannot collide with `<id>-orig-…`, so CLICKING a photo still fetches the untouched original. The QML source gate becomes a sanity ceiling (32 MB) rather than a transfer budget, since the Mac now bounds what is sent. VERIFIED: both attachments of the real message fetch from scratch on the auto path; demo fixtures now send two photos in one message and the harness screenshot shows both rendered inline, which is also the new README image. 282 tests. Deployed to fnix and to the live plugin. LR-T: blip, attachments, photos, heic, sips, cache, auto-fetch LR-D: blip, imessage-bridge LR-K: preview-max-dim, source-vs-converted-cap, prev-cache-slot LR-L: law-10, law-11 LR-R: 9711f40 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K3V19BaTrQa2HCPFYbcfTy
Why
iPhone Messages files Spam as
chat.is_filtered = 2and Filter Unknown Senders as1. The phone badge ignores both. Blip read the samechat.dband counted them, so the bar could show 3 while the phone showed 0.There is no folder setting today. The mute list is per sender/phrase, not the folder.
What
Two
bridge.confkeys, default off (previous behaviour):The Linux shim injects
--hide-spam/--hide-unknownonimsgonly. The Mac query drops those chats fromrecent,chats, andsearch(no sidebar row, no unread, no toast). Explicitthread/fromstill load a chat if you have its id.chat.is_filteredmissing (older schema) → no extra predicate.Needs
Re-run
blip-setup(or copybridge/mac/imsgto the Mac and the shim to~/bin/imsg) so an olderimsgis not handed unknown flags.Test
python3 bridge/mac/test_filtered.py— 7 cases, no macOS, no realchat.db.