Skip to content

fix: preserve log reading position through delayed media - #1103

Merged
xHeaven merged 4 commits into
dev-null-sh:productionfrom
xHeaven:fix/latest-preview-scroll
Oct 24, 2026
Merged

xHeaven merged 4 commits into
dev-null-sh:productionfrom
xHeaven:fix/latest-preview-scroll

Conversation

@xHeaven

@xHeaven xHeaven commented Oct 24, 2026

Copy link
Copy Markdown
Member

Summary

New commits on Latest and Following could hold the reading position during insertion, then push it down when their link previews resolved. On merged production, three pending previews moved the existing reading row by 20.75 CSS pixels near the top.

Near the top, the new-commit notice could also dismiss because it counted a row hidden behind the sticky tabs as seen. The notice now excludes that covered area and only marks arrivals as seen while the tab is visible.

Keep the same visible reading content in place through insertion and later media layout changes, including when starting at the top. A focused visible composer stays in place while typing; deliberate scrolling and the New commits control remain usable.

Changes

  • Retain the visible anchor through feed mutations and resizing instead of restoring it once.
  • Distinguish viewport scrolling from changes to the anchor's document position; recapture the anchor after deliberate scrolling or focus changes.
  • Release compensation during the explicit smooth return to the top, then reacquire the visible row when scrolling settles.
  • Keep native browser anchoring for initial media, and transfer ownership before an insertion when a custom anchor is captured. Restore native anchoring on navigation.
  • Preserve the scroll delta when a preview resize and deliberate viewport movement happen together.
  • Remove the top-only arrival animation and cover delayed growth/shrink, top insertion, count-only polling, scrolling and composer focus with behavior tests. Update the log documentation.

Validation

  • bun x vp test --config tests/draft-images.config.ts: 481 passing component tests, including 53 LogInsertion cases.
  • bun run test:unit: 153 passing; bun run test:types, bun run build, composer test:lint: pass. Existing unrelated no-floating-promises warnings remain.
  • composer test:type-coverage: 100%.
  • XDEBUG_MODE=coverage DB_DATABASE=latest_preview_scroll_test php -d memory_limit=-1 vendor/bin/pest --parallel --ci --coverage --exactly=100.0 --passthru-php="'-d' 'memory_limit=-1'": 4,115 passing tests, 23,067 assertions, 100% coverage in an isolated local database.
  • Controlled browser scenarios at scroll offsets 0, 1, 20 and 1500; delayed tall/landscape images; missing, empty and embedded previews; real wheel input during preview resolution; client-side lane navigation. No page errors or horizontal overflow.

Visual evidence

Real compiled frontend with controlled local Inertia, link-preview and media responses. Poll callbacks exercise the automatic insertion path. The browser demo does not use a running Laravel backend; PHP validation is separate.

Delayed preview comparison (1440 × 900, dark)

Production before After
Before delayed preview After delayed preview

Before MP4 · After MP4

Desktop reading-row drift falls from 20.75px to 0.25px; mobile viewport comparisons remain within 0.25px. Measured action CLS after the fix is at most 0.000084 on desktop and 0 on mobile. Real wheel input still moves the content by the requested distance (within 0.125px rounding).

Initial media and concurrent scrolling

Native anchoring remains active before the first arrival: existing-preview drift matches production (−0.375px desktop, 0 mobile). A controlled public scrollTo jump of 200px released in the same task as a pending-preview response now moves the reading row by 199.375px, matching production rounding. Actual simultaneous wheel/touch failure was not demonstrated.

Existing preview, no arrival Scroll + preview response in one task
Initial media Concurrent scroll and preview

Initial media MP4 · Concurrent scroll MP4 · Mobile initial MP4 · Mobile concurrent scroll MP4

Initial and concurrent-scroll states in all six viewport/theme combinations

1440 × 900, light

Initial pending Initial resolved Before concurrent scroll After concurrent scroll
initial before initial after race before race after

1440 × 900, dark

Initial pending Initial resolved Before concurrent scroll After concurrent scroll
initial before initial after race before race after

1366 × 650, light

Initial pending Initial resolved Before concurrent scroll After concurrent scroll
initial before initial after race before race after

1366 × 650, dark

Initial pending Initial resolved Before concurrent scroll After concurrent scroll
initial before initial after race before race after

390 × 844, light

Initial pending Initial resolved Before concurrent scroll After concurrent scroll
initial before initial after race before race after

390 × 844, dark

Initial pending Initial resolved Before concurrent scroll After concurrent scroll
initial before initial after race before race after

Returning from deep in the feed

Return to new commits

Desktop MP4 · Mobile MP4 · iOS touch MP4

Returns from initial reading offsets 1500 and 2600 now reach scrollY 0 and dismiss the notice. Scroll/remeasurement tests also cover interruption and resuming preservation. All six viewport/theme recordings passed; these supplemental screenshots are frames captured at 1× during video recording.

Deep-feed return across all viewports/themes

1440 × 900, light

Reading Back at the top
Reading At the top

MP4

1440 × 900, dark

Reading Back at the top
Reading At the top

MP4

1366 × 650, light

Reading Back at the top
Reading At the top

MP4

1366 × 650, dark

Reading Back at the top
Reading At the top

MP4

390 × 844, light

Reading Back at the top
Reading At the top

MP4

390 × 844, dark

Reading Back at the top
Reading At the top

MP4

Near-top notice

Before: unseen arrival loses notice After: notice stays until seen
Before notice After notice

Before MP4 · After MP4. One short commit, composer already offscreen. Only 31% of the newest row is visible below the tabs; it is now kept as unseen.

Focused composer

Composer stays focused

MP4. Draft and focus retained; measured input drift 0px.

Full viewport and theme comparisons

1440 × 900, light

Before pending Before loaded After pending After loaded
before pending before loaded after pending after loaded

1440 × 900, dark

Before pending Before loaded After pending After loaded
before pending before loaded after pending after loaded

1366 × 650, light

Before pending Before loaded After pending After loaded
before pending before loaded after pending after loaded

1366 × 650, dark

Before pending Before loaded After pending After loaded
before pending before loaded after pending after loaded

390 × 844, light

Before pending Before loaded After pending After loaded
before pending before loaded after pending after loaded

390 × 844, dark

Before pending Before loaded After pending After loaded
before pending before loaded after pending after loaded

Device verification

iPhone 17 simulator, iOS 27.0, Safari: delayed previews preserved the reading row within 0.75px. The New commits control returned to the top by touch. With the actual keyboard open, the draft remained focused at the same position (0px drift) through arrivals and late previews; the Commit button stayed visible above the keyboard. Safe areas, bottom navigation and Safari toolbars were inspected.

Reading through arrivals Composing with keyboard
iOS reading position iOS focused composer

iOS reading MP4 · iOS keyboard MP4

Native Safari also retained the notice through an actual app-background/foreground transition without changing the scroll position. This clip plays at 4× speed; it tests leaving Safari and returning rather than a desktop tab switch.

iOS notice retained after backgrounding

iOS background/return MP4

Near-top notice comparisons in all six viewports/themes

1440 × 900, light

Before After
Before notice After notice

1440 × 900, dark

Before After
Before notice After notice

1366 × 650, light

Before After
Before notice After notice

1366 × 650, dark

Before After
Before notice After notice

390 × 844, light

Before After
Before notice After notice

390 × 844, dark

Before After
Before notice After notice

Independent review

Sol 6.1, high reasoning / priority service: CODE PASS · VISUAL PASS, no actionable findings or unresolved blockers. Reviewed base 4ff5b7017a3aa130cdf3dbf9e6d320d495840613 → head 5d55bd344f026a9fcee6fc3fd2afd1e8b46a704f and all 115 files in the frozen media manifest. Independently reran 53 insertion tests and paired initial-media, concurrent-scroll, deep-return, visibility, composer, and anchoring-restoration scenarios. Broader test results are supplied evidence; native evidence and recordings were inspected through screenshots/contact sheets, without exhaustive frame playback.

Limitations

Browser scroll quantization can leave subpixel differences below 1 CSS pixel. Android SDK is unavailable; physical hardware and arbitrary network/input timing combinations were not tested. Browser evidence uses controlled responses, not a production data session.

@xHeaven
xHeaven merged commit 928473d into dev-null-sh:production Oct 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant