Skip to content

Let the digest size fit also trim leftover channel chats #454

Description

@HMarzban

Summary

The digest size fit trims only chats that sit under a changed heading. It never trims the chats of channels that are not a heading section. A document with many busy channels, or a combined mail of many documents, can pass the size limit on those chats alone. Gmail then clips the end of the mail. After #449, that end holds the closing line with the stop-all link.

Land after #449. It changes the status bars and the closing line that the fit measures.

Where

  • packages/email-templates/src/digestFit.ts:57-73: dropOldestChat walks only content_changes.sections[].chats.
  • digestFit.ts:82: an emptied chatOnly section is dropped. A channel needs the same rule.
  • digestFit.ts:116-120: the fit runs at most 500 steps. When no section chat and no passage can shrink, it returns the documents as they are, still over the limit.
  • packages/email-templates/src/digestWalk.ts:70-78: every leftover channel paints its first DIGEST_CHANNEL_LINES (5) notices, then +N more, with no limit on the number of channels. Notices arrive sorted by created_at ascending (packages/supabase/scripts/07-5-email-notifications-pgmq.sql:645), so the painted five are the oldest.
  • packages/email-templates/templates/digest.eta: after Add an "Unfollow this document" link to each document in the Change digest #449, the closing line with the stop-all link is the last thing in the mail.

What happens

Read from code, not measured. With many busy channels, in one document or in a combined mail, the leftover channel notices grow the HTML. It passes the configured limit (default 90 KB) and Gmail's 102 KB clip limit. Gmail hides the tail behind "View entire message", so the closing line and its stop-all link do not show.

Fix

In dropOldestChat (packages/email-templates/src/digestFit.ts), also scan doc.channels[].notifications. Pick the oldest notice by created_at across section chats and channel notices. The rule "never drop a changed heading; drop oldest chat first" stays as it is.

When the pick is a channel notice, do this in one step:

  • If the channel has more than DIGEST_CHANNEL_LINES notices, first cut its list to the first DIGEST_CHANNEL_LINES. The walk paints only those. Without the cut, dropping one row pulls the next hidden row into view. The HTML then does not shrink, and the step is wasted against the 500-step cap.
  • Then drop the picked notice.
  • If the channel has no notice left, drop the channel, as line 82 drops an empty chatOnly section. Otherwise the walk paints a bare # name heading.

No new export, field or helper.

Out of scope

  • DIGEST_CHANNEL_LINES, which five notices a channel shows (the oldest), the 500-step cap, grouping, and the max-KB setting stay as they are.
  • The subject count and the bell badge fall with each dropped channel notice, through countDigestItems. Dropped section chats already do this.

Acceptance criteria

  • A new test sits beside the existing fit tests in packages/email-templates/src/__tests__/engine.test.ts. It builds one document with no content_changes and one channel of 7 notices. The previews have equal length. The limit is the full HTML size minus 1. The fitted HTML is at or under the limit. Notice 1 is gone, notice 2 still shows, and more in this channel is gone.
  • A second test puts the oldest notice alone in its channel. After the fit, that channel's # name heading is gone.
  • Both new tests fail against the unchanged dropOldestChat. Observed.
  • The existing fit tests still pass, so section chats and changed headings keep their rules. Observed green.
  • The HTML-cap bullet in apps/hocuspocus.server/CLAUDE.md §Digest Email Links And Counts says the fit also drops leftover channel chats, and drops a channel left with none.

Verify

  • bun run --filter @docs.plus/email-templates test. The package script sets APP_URL and NEXT_PUBLIC_APP_URL; a bare bun test does not.
  • cd apps/hocuspocus.server && bun test tests/unit/contentChangeDigest.test.ts. It runs the fit at maxBytes 1 and must stay green.

Open decisions

  1. Once the fit cuts a long channel, its +N more count is gone. Is that acceptable? Recommended: yes. The fit runs only when the mail is over the cap. A true count would need a new payload field. The channel heading still links to the room.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions