Repository navigation
fix(attachments): send image dimensions so previews don't shift - #2262
Merged
Merged
Conversation
The relay measures each uploaded image and returns its size as `dim`. The app dropped that field, so sent images had no `imeta dim`. Readers then reserved a 360x320 loading frame and resized it when the image decoded, which moved the timeline while scrolling. Keep a well-formed `dim` from the upload result and write it into `imeta`. The dev upload broker forwards it too. Sender and receiver share one `IMETA_DIM` pattern. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Kevin Chung <[email protected]>
kchung
marked this pull request as ready for review
November 3, 2026 15:45
kalvinnchau
reviewed
Nov 3, 2026
kalvinnchau
left a comment
Contributor
There was a problem hiding this comment.
🤖 Adversarial review at 299bf44: no inline findings.
Checked:
- Every send path (channel/reply/DM/Huddle/Feedback, plus edits that copy
imeta) goes throughattachmentMessage→validateUploadResult, sodimis validated once against the sameIMETA_DIMthe receiver uses. - The native path (
nativeAttachmentUpload) and broker path both return the relay descriptor verbatim tovalidateUploadResult; malformeddimis dropped without failing the upload. - The relay
imetaallowlist acceptsdimas a singleton key; the relay computes it from the decoded image (EXIF-bearing images are rejected upstream) or the transcoded mp4 track (ffmpeg autorotates during preparation), so the reserved frame matches the decoded media.
Ran at this head: vitest run src/features/relay/attachments.test.ts src/features/relay/fold.test.ts (123 passed), browser-host/attachment-upload.test.mjs (25 passed), biome check on the touched files (clean).
Residual risk, not blocking: for videos, MediaAttachment prefers attachment.dimensions over measured dimensions for the life of the element, and the relay reports coded avc1 width/height. A non-square-pixel (anamorphic) source would therefore keep a slightly wrong frame instead of correcting after load. Agent-sent videos already behave this way.
kalvinnchau
approved these changes
Nov 3, 2026
dr0uleau
added a commit
that referenced
this pull request
Nov 3, 2026
…xecution-support-for-native-buzz-33ea2bea * origin/main: (74 commits) feat(host): harden byte lifecycle and add protected image upload (#2199) Updated onboarding (#2183) perf(relay): read each signed roster once in large channels (#2244) AIDA-2346: Keep spoilers hidden in reminder previews (#2261) fix: AIDA-2371 Keep sidebar selection pill aligned during resize (#2182) fix(relay): skip background rereads of profiles a read found absent (#2147) fix: prevent startup logo selection (#1823) fix(agents): send sign-in evidence with agent Git credentials (#2240) perf(mentions): stop scanning every member on each mention keystroke (#2246) fix(attachments): send image dimensions so previews don't shift (#2262) feat(shortcuts): add Slack-style hotkeys (#2170) perf(plugins): share host request clients across calls (#2243) fix(identity): keep federated sessions and agent grants in one keychain item (#2225) fix(profiles): evict the least recently requested profile (#2255) fix(unread): repair unread from the recovery tick only every 15 minutes (#2252) AIDA-2374: Use readable labels in chat titles (#2185) perf(profiles): keep verified names checked through a planned renewal (#2234) feat(plugins): let a plugin ask Buzz to review an install (#2059) fix(identity): sign FI builds in at first run through the native session (FOUNDATION: App.tsx, services.ts) (#2249) Place profile verification beside the verified name (#2224) ... Signed-off-by: Daniel Rouleau <[email protected]>
dr0uleau
added a commit
that referenced
this pull request
Nov 3, 2026
* commit 'c8e882165': (50 commits) Scope execution targets by harness session Read durable execution state before admission feat(host): harden byte lifecycle and add protected image upload (#2199) Updated onboarding (#2183) perf(relay): read each signed roster once in large channels (#2244) AIDA-2346: Keep spoilers hidden in reminder previews (#2261) fix: AIDA-2371 Keep sidebar selection pill aligned during resize (#2182) fix(relay): skip background rereads of profiles a read found absent (#2147) fix: prevent startup logo selection (#1823) fix(agents): send sign-in evidence with agent Git credentials (#2240) perf(mentions): stop scanning every member on each mention keystroke (#2246) fix(attachments): send image dimensions so previews don't shift (#2262) feat(shortcuts): add Slack-style hotkeys (#2170) perf(plugins): share host request clients across calls (#2243) fix(identity): keep federated sessions and agent grants in one keychain item (#2225) fix(profiles): evict the least recently requested profile (#2255) fix(unread): repair unread from the recovery tick only every 15 minutes (#2252) AIDA-2374: Use readable labels in chat titles (#2185) perf(profiles): keep verified names checked through a planned renewal (#2234) feat(plugins): let a plugin ask Buzz to review an install (#2059) ... Signed-off-by: Daniel Rouleau <[email protected]> Co-authored-by: Codex <[email protected]>
ljknight
added a commit
to ljknight/buzz-app
that referenced
this pull request
Nov 3, 2026
…ection * origin/main: (39 commits) Authorize local apps to use Buzz MCP tools (block#2211) feat(bestie): choose the private channels Bestie can read (block#2036) Polish message actions, spacing, and membership notices (block#2258) test(unread): prevent startup catch-up in receipt reserve journey (block#2274) test(search): wait for rejected join clearance to settle (block#2278) test(reactions): provide stable emoji media for icon rendering (block#2279) feat(profiles): reserve profile room for an open channel's roster (block#2269) feat(host): harden byte lifecycle and add protected image upload (block#2199) Updated onboarding (block#2183) perf(relay): read each signed roster once in large channels (block#2244) AIDA-2346: Keep spoilers hidden in reminder previews (block#2261) fix: AIDA-2371 Keep sidebar selection pill aligned during resize (block#2182) fix(relay): skip background rereads of profiles a read found absent (block#2147) fix: prevent startup logo selection (block#1823) fix(agents): send sign-in evidence with agent Git credentials (block#2240) perf(mentions): stop scanning every member on each mention keystroke (block#2246) fix(attachments): send image dimensions so previews don't shift (block#2262) feat(shortcuts): add Slack-style hotkeys (block#2170) perf(plugins): share host request clients across calls (block#2243) fix(identity): keep federated sessions and agent grants in one keychain item (block#2225) ... # Conflicts: # src/features/messages/ThreadPanel.tsx
arividar
pushed a commit
to minniai/minni-buzz-app
that referenced
this pull request
Nov 4, 2026
…k#2262) ## Why Image attachments move the timeline when they load. This happens most with wide, short screenshots. Scroll up through a channel, and the content jumps as each image appears. The relay measures each uploaded image and returns its size as `dim`. The app dropped that field when it sent the message. So images sent from the app had no `imeta dim`. Readers then reserved a 360×320 loading frame. When the image decoded, the frame shrank to the real size, and everything below it moved. Agent uploads already send `dim`, so their images did not move. ## What - Images and videos sent from the app now carry their size. - Readers reserve the correct frame before the image loads, so the timeline does not move. - Readers on older app versions also get the correct frame, because the size travels with the message. ## How - `validateUploadResult` keeps a well-formed `dim` from the relay's upload result. A malformed value is dropped and the upload continues. - `attachmentMessage` writes `dim WxH` into `imeta`. All app send paths use it: messages, replies, new DMs, Huddle and feedback. - The dev upload broker (`browser-host/attachment-upload.mjs`) forwards `dim` too, so broker and native uploads match. - The sender and the receiver (`parseAttachments`) share one `IMETA_DIM` pattern, so they cannot disagree about a valid value. ## Before and after https://github.com/user-attachments/assets/7db7de64-59e6-4214-925c-8208ef714207 ## Risk Low. The change adds one optional, validated `imeta` field. The relay already accepts `dim` in `imeta`. Messages sent before this change still have no size, so they still move on first load. ## Testing - New tests in `attachments.test.ts` send an upload result with `dim` through to `imeta` and back through the receiver. Malformed values are dropped. The test fails without the fix. - The broker test checks that `dim` is forwarded. It fails without the forward. - `just desktop` with the organization sign-in against the live community: sent wide screenshots, reloaded and scrolled past them. New images kept their frame. Older images still moved. No browser journeys were added or removed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Kevin Chung <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Image attachments move the timeline when they load. This happens most with wide, short screenshots. Scroll up through a channel, and the content jumps as each image appears.
The relay measures each uploaded image and returns its size as
dim. The app dropped that field when it sent the message. So images sent from the app had noimeta dim. Readers then reserved a 360×320 loading frame. When the image decoded, the frame shrank to the real size, and everything below it moved. Agent uploads already senddim, so their images did not move.What
How
validateUploadResultkeeps a well-formeddimfrom the relay's upload result. A malformed value is dropped and the upload continues.attachmentMessagewritesdim WxHintoimeta. All app send paths use it: messages, replies, new DMs, Huddle and feedback.browser-host/attachment-upload.mjs) forwardsdimtoo, so broker and native uploads match.parseAttachments) share oneIMETA_DIMpattern, so they cannot disagree about a valid value.Before and after
before-after-labeled.mp4
Risk
Low. The change adds one optional, validated
imetafield. The relay already acceptsdiminimeta. Messages sent before this change still have no size, so they still move on first load.Testing
attachments.test.tssend an upload result withdimthrough toimetaand back through the receiver. Malformed values are dropped. The test fails without the fix.dimis forwarded. It fails without the forward.just desktopwith the organization sign-in against the live community: sent wide screenshots, reloaded and scrolled past them. New images kept their frame. Older images still moved.No browser journeys were added or removed.
🤖 Generated with Claude Code