Skip to content

fix(desktop): anchor history pagination through visual commit - #7006

Open
wesbillman wants to merge 6 commits into
mainfrom
pinky/scroll-history-transactions
Open

fix(desktop): anchor history pagination through visual commit#7006
wesbillman wants to merge 6 commits into
mainfrom
pinky/scroll-history-transactions

Conversation

@wesbillman

@wesbillman wesbillman commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Pinky is opening this PR on Wes’s behalf.

Summary

Keep an older-page request reserved until its rows and metadata have crossed React deferral, the input-settle gate, and stable DOM measurement. A network response alone no longer frees the next page to load, and programmatic layout scrolls cannot create reader intent.

  • Admit messages, exhaustion proof, unread boundary, thread summaries, and the history receipt together. Require quiet input plus stable frames; do not admit a prepend merely because a fixed deadline elapsed.
  • Keep Virtua as the single history-anchor owner. Extend the existing pinned patch with key-based size reconciliation and surviving-neighbor anchoring for mixed prepend/delete/marker changes. Compensate measurements above the reading row, not that row’s own grouping-height change. Preserve scalar/default and unkeyed behavior.
  • Stage reconnect/head refreshes before publishing. Follow relay-issued composite cursors, verify the first retained join, and preserve loaded depth—including a concurrent older request. On failure, retain the reading window with Retry / Load latest recovery.
  • Remove only a rejected send’s optimistic row rather than rolling the entire window back. Hydrate reactions into the authoritative window store. Avoid repeatedly reconciling all cache-only replies for every history row.
  • Add mounted lifecycle, installed ESM/CJS patch, relay-shaped cursor-model, and browser regressions. Extract the existing DM participant derivation only to keep ChannelPane under the repository size limit.

TanStack Query still owns network/cache operations; Virtua still owns virtualization and history offset compensation. No library replacement, relay change, speculative prefetch layer, or second scroll-position system.

Related issue / overlapping work

CI/review follow-up — 4c25af1660fa7890cee8340f201ecab26ba8f18f

  • Accepted deletion: remove the event from the current authoritative pages/aux/live storage as well as the flattened cache. Cursor bounds and publication receipts are unchanged. A mounted real-QueryClient mutation test holds the delete request, commits an older page and a live row, then verifies successful deletion and later reprojection preserve those concurrent writes.
  • Live delivery into exhausted history: an exhausted window has no unretained older gap; accept backdated live events there. The original reconnect test's first failing assertion injects an event at now - 300s, older than the seeded channel. Standalone browser cases now cover both current-time and backdated arrivals without any reader gesture or reconnect.
  • Reconnect gap rendering: buffering freezes the retained tail boundary, not original membership. Recovered rows between retained IDs now render; only arrivals after the tail remain buffered. The full >live-subscription-limit reconnect journey passes.
  • Recovery intent lifetime: consume a unique Load latest token at fetch entry and retain intent on that fetch's AbortSignal across actual TanStack retries. Cancellation cannot arm a future unrelated refresh. A matching-token cleanup also covers unmount before invalidation begins; community reset clears the WeakSet.
  • Copy-link fixture: use a distinct huddle ID instead of reusing the seeded custom-emoji target's signed-event ID. Copy-link eligibility logic was not weakened.

Follow-up validation

  • On exact committed head 4c25af1660fa7890cee8340f201ecab26ba8f18f, all applicable pre-push lanes passed, including 5,835/5,835 desktop tests, TypeScript, desktop lint/policy checks and differential file-size checks. Pre-commit changed no files; working tree clean after push.
  • Fresh E2E build of the production sources now in this head: 76/76 headless Chromium tests passed across history-transactions, scroll-history, overscroll-boundary, channel-window-mock-paging, timeline-no-shift, relay-reconnect, relay-reconnect-affordance, message-copy-link, empty-edit-delete, human-edit-agent-content, channel-dense-second-reach, channel-head-restart, and virtualization. This includes all four persistent failing smoke cases from the previous head. This was a selected cross-file matrix, not the entire smoke suite.
  • After adding only test changes, 3/3 browser cases passed on the same build: two new standalone fresh-channel live-delivery cases plus the repeated >subscription-limit reconnect case. Thus 78 distinct browser cases, not a single 78-case run.
  • Combined store/lifecycle/recovery/buffering tests passed 53/53 before the full hook suite. Seven recovery tests drive the real query hook and DOM controls through the Tauri seam, including actual send cancellation, channel navigation, retry: 1, exhausted Retry/Load latest and pre-invalidation unmount.
  • GitHub CI at 4c25af16: run 33216835648 completed successfully, including Desktop Core, smoke shards 1–4, both integration shards and macOS build. Both requested GitHub re-reviews approved that exact head. The test-only follow-up below has a new CI/review cycle; these results are not attributed to the newer commit.

Middle-insertion regression — 318bfe31c7a8729b5974c0f995a6bd8b20915bea

Test-only addition; production sources and the Virtua patch are unchanged from 4c25af16.

  • Added a reconnect workflow retaining five pages / 250 messages. A missed row is inserted at zero-based message index 165, above the reading anchor at index 169, in the first freshly verified join page. The test proves fetched-page membership, DOM admission above the reader, the exact retained ID sequence plus one middle insertion, and unchanged first/last IDs. This cannot pass by hiding the inserted row or exercising only prefix shift.
  • The anchor stayed at 42px relative to the viewport: 0px maximum drift across 252 animation frames in the final run. The spec attaches indices/offset/sample metrics as middle-insertion-anchor.json.
  • Mutation control: disabled only the keyed structural-update dispatch (action 10) in a temporary copy of the built bundle, leaving production files and installed dependencies untouched. This exact test then failed its frame oracle with 58px drift. The normal bundle passed. This validates that the existing itemKey reconciliation path owns compensation even when shift=false; no second scroll compensator was added.
  • Final browser check: entire history-transactions.spec.ts and relay-reconnect.spec.ts files 26/26 passed, no retries. Fresh E2E build used unchanged 4c25af16 production sources and the exact test bytes subsequently committed here; pre-commit changed no bytes.
  • At exact committed head 318bfe31c, all applicable pre-push gates passed: 5,835 desktop tests, typecheck, lint/policy, branch-skew and file-size gates. Working tree clean after push.
  • New CI run 33221480249 is pending. Security review was skipped, not cleared. Native WKWebView/physical input, visual evidence, and perf(desktop): make scrollback paging paint from memory and stop page cascades #6601 merge-order reconciliation remain outstanding.

Original implementation validation

Verified on f0335c3b1859712818004b1cf0e4dfb810081445 (historical evidence; subsequent findings/fixes are above):

  • Pre-commit formatting and every applicable pre-push lane passed: branch skew, push-head scope, differential file-size checks, desktop lint/policy checks, TypeScript, and 5,825/5,825 desktop tests. Lint reports existing warnings/info in untouched files.
  • Fresh pnpm build:e2e through the smoke script, then 66 browser tests passed; one pre-existing navigation test skipped:
    pnpm test:e2e:smoke history-transactions.spec.ts timeline-no-shift.spec.ts \
      scroll-history.spec.ts virtualization.spec.ts channel-dense-second-reach.spec.ts \
      channel-window-mock-paging.spec.ts channel-head-restart.spec.ts \
      overscroll-boundary.spec.ts navigation.spec.ts
  • Coverage includes exact one-page-per-gesture behavior; receipt/deferral/cancellation; touch, keyboard and scrollbar intent; bounded viewport fill; reconnect racing pagination; DM beginning markers; mixed deletion/live metadata; failed-send rollback; failed Retry / Load latest; unchanged-head recovery; late reflow; navigation; and dense-second reachability.
  • Per-frame no-shift traces reported 0px maximum drift in the measured mixed-media, prepend/reflow, and thread scenarios. New history transaction scenarios require under 5px drift. This is measured browser evidence, not a claim about all inputs/platforms.
  • Scalar-size compatibility regression reproduced r.slice is not a function in both installed module formats before the fix; all 20 installed-patch tests passed afterward.
  • Frozen-lockfile install passed. Reversing the patch reproduced its original blob hashes for all four patched files; reapplication exactly reproduced installed ESM/CJS/type bytes. Patch-context whitespace is inherited from upstream; source diff whitespace checks pass.

Review and remaining limits

  • Independent review covered refresh/cursor semantics, receipt lifetime, and the Virtua patch. Brain closed the recovery-cancellation blocker at 4c25af16 and withdrew the middle-insertion concern after tracing the actual patched React export and checking the measured regression/control. His source-level retraction confirms action 10 updates the cache length before the ordinary length-update guard, so the same commit cannot also take case 5. Both jedwards27 and wpfleger96 approved 4c25af16. The new test-only commit requires fresh reviewer disposition; no approval is carried forward by assumption.
  • First join is freshly verified; deeper retained boundaries rely on NIP-CW’s immutable-history contract. This does not repair arbitrary historical backfill.
  • Not yet validated on physical macOS trackpad input / native WKWebView. Browser tests use headless Chromium and the mock bridge; they do not prove native momentum behavior or live-relay recovery. No native app was launched for this validation.
  • Before merge: green/explained CI, reviewer clearance, exact-range security review, explicit reconciliation with perf(desktop): make scrollback paging paint from memory and stop page cascades #6601, and native/visual validation. The template's before/after visual artifact is still outstanding. No approval or merge is requested automatically.

Reserve one older-page transaction through deferred rendering and stable
measurement. Admit rows and metadata together, reconcile Virtua sizes by key,
and stage reconnect refreshes without evicting the reading window.

Add recovery controls, concurrent-send rollback protection and mounted/browser
regressions for reader intent, cancellation, mixed updates and late reflow.

Co-authored-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman
wesbillman requested a review from a team as a code owner August 28, 2026 21:17
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 00e61eafa917d296104006576b7a2ddbfd58bb5a...55be15c74c6155af4f6def93ff3f27f19973747d.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 55be15c74c6155af4f6def93ff3f27f19973747d to authorize a new review.
Any previous review applies only to its recorded range.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent reviewed exact head f0335c3b1859712818004b1cf0e4dfb810081445 against base c432a111ca9ddd31a85e1312d5995f8b92191b82.

Blocking findings

  1. High — successful main-timeline deletes are not removed from the authoritative window. useDeleteMessageMutation.onSuccess only filters channelMessagesKey (desktop/src/features/messages/hooks.ts:883-888), but this PR makes channelWindowKey authoritative: the neighboring edit path explicitly updates the window first because every live merge re-flattens it over the message cache (desktop/src/features/messages/hooks.ts:962-975). A successful delete can therefore remain visible or be resurrected by the next projection/live merge. This is not theoretical: CI Smoke E2E shard 2 failed all three attempts for both ordinary and owned-agent deletion (empty-edit-delete.spec.ts:51, human-edit-agent-content.spec.ts:119), always receiving a visible row after the 5s hidden assertion; an independent exact-head local rerun reproduced both failures.

    Author action: functionally remove the event from the current authoritative channel window (pages/live overlay/auxiliary storage as applicable), then project it without restoring a captured snapshot that could erase concurrent paging/live writes. Add a real-QueryClient regression proving the deletion survives reprojection while concurrent window updates remain intact, and rerun both deletion E2Es plus the full smoke shard.

  2. High — fresh live traffic can disappear before reconnect is even attempted. CI Smoke E2E shard 4 failed all three attempts in relay-reconnect.spec.ts:657 at the pre-disconnect assertion on line 669: after mock live delivery, the timeline never contained reconnect e2e seen before disconnect within 5s. An independent exact-head focused rerun failed at the same assertion. Since execution never reaches the disconnect on line 673, this is a live-tail admission failure, not merely uncertainty in reconnect backfill; users at the apparent bottom can silently miss a newly delivered message.

    Author action: repair bottom/live-tail admission and add a deterministic fresh-channel live-arrival regression before the reconnect/cursor-race scenario, then prove the >subscription-limit reconnect backfill.

Validation and integration notes

  • Exact-head Desktop unit suite: 5,825/5,825 passed; typecheck passed.
  • Focused pagination/revalidation/reaction/Virtua tests: 54/54 passed. history-transactions.spec.ts: 7/7 passed in Chromium, including deep-history reconnect, concurrent older request, deletion/live metadata during prepend, Retry/Load latest, and <5px anchor checks.
  • Mutation checks caused the expected failures when visual-commit acknowledgement, concurrent-send rollback preservation, or fresh-cursor revalidation were weakened.
  • The virtua@0.49.3 ESM and CJS patches were checked for parity across keyed structure, late measurement, reader-input retirement, and estimate forms.
  • PR #6601 edits the same window store, pagination, timeline, settle-gate, and E2E contracts with real merge conflicts. These are competing semantics; whichever proceeds must reconcile and re-prove behavior rather than mechanically combine diffs.
  • Confidence gaps, not additional blockers: native WKWebView/physical-trackpad momentum and scrollbar behavior, live-relay observation, and screen-reader recording remain unverified. An interactive macOS tester should validate a dense live channel, one-page-per-gesture, late media/grouping reflow, and <5px anchoring after the code defects are fixed.

Current CI is blocked with Desktop and Smoke shards 2–4 failed. Verification owner after author fixes: reviewer reruns the focused dual-cache/concurrency, delete, live-arrival/reconnect, unit/typecheck, and relevant full smoke evidence at the new exact head.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Combined review from three independent passes at exact head f0335c3: a source-level review, a CI-failure/diff analysis, and a live-relay E2E run against the PR-built desktop bundle. Requesting changes — two blocking defects, both confirmed by deterministic exact-head CI failures (3/3 retries exhausted) and independently root-caused in source.

Blocking

1. IMPORTANT — Successful deletes only mutate the derived message cache, so the authoritative window resurrects the row. useDeleteMessageMutation.onSuccess filters only channelMessagesKey (desktop/src/features/messages/hooks.ts:883-888), but this PR makes channelWindowKey the projection source: projectChannelWindowMessages() rebuilds the message cache from the window store (projectChannelWindow.ts:12-23), so any subsequent live event, scrollback page, or explicit projection restores the deleted row. The adjacent edit path already documents and handles this dual-cache rule. CI confirms the user-visible failure: empty-edit-delete.spec.ts:51 and human-edit-agent-content.spec.ts:119 both fail 3/3 with the deleted row still visible after 5s.

Fix: remove the event from every applicable current-window location (page rows/aux and live overlays), then reproject from that current window — do not restore a captured snapshot, which would erase concurrent page/live commits. Add a real-QueryClient regression that deletes while concurrent window state advances and proves reprojection cannot resurrect the row.

2. IMPORTANT — A live-tail event is not reliably admitted while the channel appears at bottom. relay-reconnect.spec.ts:657 fails 3/3 at line 669 — before the disconnect: the emitted seenBeforeDisconnect live event never enters the rendered timeline on a fresh channel that should be at bottom. The affected path is the new semantic-bottom/buffering handoff (useAdmittedTimelineSnapshotuseBufferedTimelineMessages, driven from MessageTimeline.tsx:254-267, 398-424), which can freeze the tail off a virtualizer bottom-state transition even though the reader never established scrollback intent. This also blocks reconnect validation, since the test never reaches the reconnect.

Fix: make a live event delivered to an apparently-bottom fresh channel enter the admitted snapshot deterministically; add that as a standalone regression before re-proving the greater-than-subscription-limit reconnect journey.

Both failure families are absent from main: CI succeeded at this PR's merge-base a3730784 and again at c432a111 on the same smoke lanes ~30 minutes before this run. Also needing triage under the same umbrella: message-copy-link.spec.ts:160 fails 3/3 (a pending row exposes a copy-link surface it must not), consistent with the pending-only reconciliation filter in channelWindowReconciliation.ts.

Merge-ordering (unresolved, needs an explicit decision)

Open #6601 is a material competing implementation of these same paths — the PR body itself says both must be reconciled before either merges. A merge-tree check between #6601's head d73ba9c19 and this head produces content conflicts in channelWindowStore.ts, pageOlderMessages.ts, MessageTimeline.tsx, TimelineMessageList.tsx, useSettleGatedPrependMessages.ts, scroll-history.spec.ts, and virtualization.spec.ts. These are semantic, not mechanical — whichever lands second needs real reconciliation and re-review.

Non-blocking

  • useHistoryPagination.start() reserves the page synchronously and retirement paths (channel switch, unmount, explicit intent, error, undefined receipt, stale generation) were all traced and hold; but a Tauri invoke that never settles wedges pagination for that channel with no liveness bound. Worth either a defensive bound on the request or an explicit comment stating why the invoke is trusted to settle.
  • The held-prepend state in useSettleGatedPrependMessages has no dev-visible signal; a stuck hold in the field would be invisible. A debug counter would help.
  • reconcileFetchedChannelWindow's liveSummaries filter relies on object identity (!==) across a parse boundary — pin it with a comment or test.
  • The extended virtua@0.49.3 patch is a large behavioral fork carried in minified vendor output. The installed ESM/CJS tests are unusually strong, but upstream divergence is a standing maintenance cost worth acknowledging in the patch header.

What held up under independent verification

  • Live-relay E2E at this exact head (real signed events through relay ingest, dedicated relay/Postgres/Redis/MinIO stack): repeated upward pagination (50→121 rows across 5 real window requests, 0.00px anchor drift), rapid channel switch mid-pagination (no cross-channel row leakage), and relay restart during the receipt/visual-commit gap (0.00px drift, history still pageable) — all passed.
  • Reconnect revalidation stages off-cache, follows exact composite cursors, verifies the first join with a fresh page, re-reads the current tail before synchronous publication, and leaves the retained store untouched on failure.
  • Failed-send rollback is correctly narrowed to the optimistic id, preserving concurrent history/live writes.
  • The store revision/generation tokens correctly retire stale in-flight pages, and the useUpwardPaginationWheel timer→deadline rewrite is a real simplification.

Native WKWebView / physical-trackpad behavior remains unvalidated, as the PR body already acknowledges.

… updates

Scope explicit Load latest intent to one fetch and its retries, retiring
unclaimed intent after cancellation. Update the authoritative window on
accepted deletion without erasing concurrent history or live arrivals.

Admit backdated live rows in exhausted windows and reconnect gap rows before
the buffered tail. Add real-hook and browser regressions; give the huddle
copy-link fixture its own signed-event id.

Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
@wesbillman

Copy link
Copy Markdown
Collaborator Author

Pinky is commenting on Wes’s behalf.

Pushed follow-up 4c25af1660fa7890cee8340f201ecab26ba8f18f for the blocking findings. Re-review requested; this is not an approval/merge claim.

  1. Deletes: the accepted mutation removes its event from the current authoritative pages/aux/live storage and the derived cache. No saved-window rollback. The mounted regression holds deletion in flight while an older page and live row commit, then proves both survive success and reprojection. Both ordinary and owned-agent delete E2Es pass.
  2. Initial live arrival: the exact failing fixture is backdated by 300 seconds in an exhausted channel. mergeLiveChannelWindowEvent rejected it before it reached semantic-bottom buffering. Restricting the older-boundary rejection to open history windows fixes that mechanism. Standalone cases now prove current-time and backdated live delivery without a reader gesture or reconnect. This finding did not require changing bottom-pin behavior.
  3. Reconnect after that first assertion: the complete run then exposed fetched gap rows hidden by membership-based buffering. Freezing the tail boundary instead admits recovered interior rows while still buffering newer tail output. The >subscription-limit reconnect case now passes end to end.
  4. Copy-link: the huddle fixture reused the seeded custom-emoji target's signed ID ("d".repeat(64)) with a different event kind. Giving it a distinct ID fixes the test without loosening pending/huddle copy-link guards.
  5. Recovery controls: the separate final review found Load latest intent surviving cancellation and being lost on query retries. It is now claimed per fetch, survives that fetch's retries, and cannot leak to a later fetch; seven real-hook/DOM tests cover these boundaries.

Verification: full pre-push gate at this exact head: 5,835/5,835 desktop tests, typecheck, lint/policy and file-size checks passed. Fresh-build cross-file browser matrix of the same production sources: 76/76 passed, covering all four previously persistent smoke failures and anchor/reflow/paging regressions. Then two new standalone live-arrival tests plus the reconnect case passed 3/3 on that unchanged build. New complete CI run is pending; I have not claimed full local smoke-shard or CI success.

Remaining: reviewer clearance, security review for the new exact range, #6601 merge-order/semantic reconciliation, and physical macOS trackpad/native WKWebView plus before/after visual validation. PR body updated with exact evidence and limitations.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Re-review at exact head 4c25af1660fa7890cee8340f201ecab26ba8f18f (base c432a111ca9ddd31a85e1312d5995f8b92191b82): approved. Three independent passes found the previous delete-resurrection and live-admission blockers repaired, with no remaining author-actionable defect.

Prior blockers cleared

  1. Authoritative deletes preserve concurrent state. useDeleteMessageMutation now removes the accepted event from the current window and derived cache (desktop/src/features/messages/hooks.ts:875-900). removeEventFromChannelWindow removes it across page rows/auxiliary rows and live overlays without rewinding cursor, revision, or generation metadata (channelWindowStore.ts:248-277). The mounted real-QueryClient regression holds deletion in flight, commits an older page and concurrent live write, then proves deletion survives later projection while those writes remain (historyPaginationLifecycle.test.mjs:832-933). Removing the production window update makes that regression fail; restored head passes.

  2. Exhausted-history live delivery is admitted. Below-boundary live rows are rejected only while the oldest page has more history (channelWindowStore.ts:192-230). Once exhausted, no unresolved retained gap exists, so both current and backdated live rows enter the overlay. Reverting the condition fails the dedicated store regression. Exact-head browser coverage passes both no-gesture fresh-arrival cases and the greater-than-subscription-limit reconnect journey.

  3. Recovered gaps render without releasing the buffered future tail. useBufferedTimelineMessages.ts:20-38 freezes a retained tail boundary rather than frozen membership: recovered rows before the tail render, newer rows remain buffered, and deletion/replacement of a frozen ID fails open to current authoritative messages rather than stale objects.

  4. Load-latest intent is scoped to one fetch lifecycle. channelWindowRefreshIntent.ts:5-29, hooks.ts:314-364, and HistoryRefreshNotice.tsx:43-77 claim intent at query entry, retain it across actual TanStack retries via that fetch's AbortSignal, clear only matching unclaimed intent on cancellation/unmount, preserve retained history on exhausted retry, and suppress stale post-navigation effects. Real-hook/DOM tests cover send cancellation, channel navigation, retry, exhausted Retry/Load latest, and pre-invalidation unmount.

Exact-head evidence

  • Full Desktop unit package: 5,835/5,835 passed across 83 suites; Desktop typecheck passed.
  • Fresh E2E builds: focused systems matrix 29/29 passed; broader product matrix 36/36 passed, covering ordinary/owned-agent/thread deletes, copy-link cases, history transactions, fresh/backdated exhausted-window live delivery, and reconnect/backfill.
  • Both targeted production mutations failed their intended regression and passed after restoring the exact head.
  • GitHub smoke shards 1–4, both Desktop E2E integration shards, macOS Desktop build, Windows Rust, relay E2E seam, mobile, web, and release-candidate build are green at review time. Desktop Core remains in progress; the named gate owns completion.

Confidence gaps / integration gates — non-blocking to this code review

  • Author action: none from this re-review.
  • Verification owner: CI for the still-running Desktop Core gate; reviewer/tooling for native WKWebView, physical-trackpad momentum/rubber-band/scrollbar behavior, native visual evidence, and screen-reader announcement observation.
  • The exact-range security workflow was skipped after marking the previous review stale; the security gate owner must provide the required disposition. This is not converted into author rework without a concrete finding.
  • Open #6601 materially overlaps the channel-window/timeline/settle-gate design. Merge ordering requires semantic reconciliation and a fresh exact-head review of whichever implementation lands second, not mechanical conflict resolution.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Re-reviewed at head 4c25af1. Both blocking findings from the previous review are addressed, with regression coverage, and full CI is now green — including the four previously-failing smoke specs (3/3-retry deterministic failures at the prior head), which is the strongest possible confirmation the fixes land where the defects were.

  1. Delete resurrection — fixed. useDeleteMessageMutation.onSuccess now removes the accepted target from the authoritative window store via mapChannelWindowEvents returning null (page rows, page aux, liveOverlay, liveAux) before filtering the derived cache, preserving page cursors and the store's revision/generation. The new mounted real-QueryClient regression holds deletion in flight while an older page and a live row commit, then proves a later reprojection cannot resurrect the row — exactly the concurrency shape requested, with no snapshot restore.

  2. Live-tail admission — fixed, one seam earlier than the review hypothesized. The actual defect was mergeLiveChannelWindowEvent rejecting any live row older than the retained oldest row even on an exhausted window; the predicate now rejects below-boundary rows only while oldestPage.hasMore. The companion useBufferedTimelineMessages change correctly freezes a tail boundary rather than exact membership, so reconnect gap-fills before the tail are admitted while newer output stays buffered. New standalone browser regressions cover both now and backdated arrivals on a fresh exhausted channel before the reconnect journey runs.

  3. The message-copy-link spec change is a genuine test repair (the huddle fixture had reused the seeded custom-emoji reaction target ID with a conflicting kind), not a weakened assertion — the guard assertions are unchanged.

  4. The new channelWindowRefreshIntent recovery-token mechanism (consumed at fetch entry, scoped to that fetch's AbortSignal across TanStack retries, reset at the community boundary) is cleaner than the durable-flag approach it replaces and does not touch the pagination reservation, reconnect cursor traversal, or rollback paths previously verified — including the live-relay E2E pass at the prior head (0.00px anchor drift across repeated pagination, channel-switch, and relay-restart journeys), which remains valid for those unchanged paths.

Reminder outside this PR's control: open #6601 is a competing implementation with semantic conflicts against this branch in seven files; whichever lands second needs real reconciliation and re-review. That is a merge-ordering decision, not a defect here.

Non-blocking notes from the previous review (liveness bound on the pagination reservation, held-prepend observability, virtua-fork maintenance cost) remain open as optional follow-ups.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Re-review of the new head after my earlier changes-requested review — both concerns are addressed.

Delete resurrection via window reprojection: fixed at the root. Deletion now removes the event from the authoritative channel-window store itself (nullable mapChannelWindowEvents, cursors/revision preserved), so a later older-page fetch can't reproject it back. Verified three ways: source trace, the previously-failing smoke shards now green in CI at this head, and a live headless E2E run (70-message history, in-app delete, one genuine older-window fetch — target stayed gone after reprojection).

Fresh at-bottom live-tail admission: also fixed at the root — older rows are rejected only when a real hasMore gap exists, so a fresh at-bottom channel admits live-tail events again. Confirmed by CI and a real-relay E2E run (delivery rendered in ~166 ms with no gesture).

One E2E note for transparency: an initial live probe flagged remote kind-5 deletes as not taking effect, but adjudication showed identical behavior on base and head — the raw deletion carried only an e tag while client kind-5 subscriptions are #h-scoped, so it's a pre-existing scoping behavior outside this PR, not a regression.

Non-blocking items:

  • The #6601 semantic reconciliation the PR body calls out still needs to happen before merge.
  • Minor: useHistoryPagination.start() has no liveness bound and there's no diagnostic if a prepend gets stuck — fine to leave, but worth a thought if pagination bugs recur.
  • Minor: the vendored virtua fork isn't labeled as a fork; a short comment on why/what diverged would help future readers.
  • Native WKWebView/trackpad behavior wasn't validated in this pass (headless-only).

CI is fully green at 4c25af16 (26/26 including Desktop Core and all four smoke shards that carried the original failures). No blockers from my side.

Retain five history pages and insert a missed row inside the first refreshed join page above the reader. Assert the exact ID sequence, fetched-page membership, mounted row, and frame-by-frame viewport stability. Attach the measured indices and drift to the browser report.

Signed-off-by: Pinky <5f5ab050ec58ae208332edd544ebf705221e24c1b86d82a6ca07038a7a8f6ac9@buzz.block.builderlab.xyz>
@wesbillman

Copy link
Copy Markdown
Collaborator Author

Pinky is commenting on Wes’s behalf.

Pushed test-only follow-up 318bfe31c7a8729b5974c0f995a6bd8b20915bea. Production code is unchanged from the approved 4c25af16 head.

The remaining middle-insertion anchoring question is now measured:

Reconnect fixture Measurement
Retained window 5 pages / 250 messages
Interior insertion index (zero-based) 165
Reading anchor index before insertion 169
Anchor viewport offset 42px
Maximum drift over 252 frames 0px
Control with keyed dispatch disabled 58px drift; test fails

The new test verifies fetched-page membership, the mounted inserted row above the reader, and the exact old ID sequence with one middle insertion and unchanged first/last IDs. The control changed only action-10 dispatch in a temporary copied browser bundle—not production sources or installed dependencies.

TimelineMessageList supplies itemKey; the patched React Virtua path dispatches keyed reconciliation before the ordinary length-update branch. Thus shift=false does not leave this mutation without an anchoring owner. No production fix was needed for this question.

Validation: complete history-transactions + relay-reconnect files 26/26 passed with no retries. Exact-head push gates passed, including 5,835 desktop tests, typecheck and lint/policy/file-size checks. New CI is pending. Both reviews and applicable CI were green at 4c25af16; requesting a bounded re-review of the new test only.

Still not merge-cleared: exact-range security disposition, native WKWebView/physical-trackpad and visual evidence, and explicit #6601 semantic merge-order reconciliation. No approval or merge performed.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent re-reviewed exact head 318bfe31c7a8729b5974c0f995a6bd8b20915bea against base c432a111ca9ddd31a85e1312d5995f8b92191b82: approved. The two complementary changed-head passes found no author-actionable defect. This head adds only the 145-line middle-insertion regression to the production implementation already approved at 4c25af1660fa7890cee8340f201ecab26ba8f18f.

High-risk contracts traced

  • The new journey retains five pages, chooses an interior gap above the reader in the freshly fetched reconnect join page, disconnects before injecting the missed two-line row, proves authoritative-page membership and the exact old ID sequence plus one insertion with unchanged ends, proves the row mounted above the anchor, then samples every frame at <5px drift (desktop/tests/e2e/history-transactions.spec.ts:157-296). This does not pass by hiding the row or exercising prefix/prepend shift only.
  • The production owner remains Virtua: TimelineMessageList supplies stable itemKey with shift={isPrepend} (desktop/src/features/messages/ui/TimelineMessageList.tsx:750-760). For this non-prepend structural change, the pinned ESM and CJS patch forms reconcile sizes by key and move the surviving visible anchor before ordinary length handling (patches/virtua@0.49.3.patch:74-98,279-305,373-382).
  • Reconnect still freshly verifies the first exact join before reusing deeper immutable pages, publishes against a current reread, and retains the published reading window on failure (desktop/src/features/messages/lib/revalidateChannelWindow.ts:11-99; desktop/src/features/messages/hooks.ts:314-378). Delete/send/live projection, pagination-reservation retirement, recovery retry/cancellation, and cursor traversal have no production delta from the prior approved head.

Validation at exact clean head

  • New middle-insertion regression: 1/1 passed; full transaction file: 8/8 passed.
  • Causal mutation removing the stable production itemKey: failed 3/3 with a reproducible 58px jump (42px → 100px); restored exact head: 1/1 passed.
  • Prior blocker matrix at this head: deletion 6/6 passed; fresh/backdated live plus greater-than-subscription-limit reconnect 3/3 passed.
  • Desktop unit package: 5,835/5,835 passed; just desktop-typecheck passed; frozen install and fresh E2E build passed; git diff --check 4c25af1..318bfe3 passed.
  • A separate fresh exact-head build and focused middle-insertion run also passed (1/1, 14.3s). Installed patched ESM and CJS outputs were inspected for parity.

Findings and ownership

  • Blocking findings: none.
  • Author action: none.
  • Verification owner: CI/release gate for completion of exact-head run 33221480249; security gate owner for the skipped exact-range security job; native reviewer/tooling for WKWebView, physical-trackpad momentum/rubber-band/scrollbar, visual artifact, and screen-reader observation.
  • Residual risk: Chromium DOM geometry and exact cache/window ordering are proven; native macOS input/visual/AX behavior is not independently witnessed here. Open #6601 remains a semantic merge-order gate across the window store, pagination, timeline/list, settle gate, and E2Es—including opposing settle-deadline behavior. Whichever lands second needs deliberate reconciliation and fresh exact-head behavioral proof, not a mechanical conflict resolution.

At submission time, exact-head CI had no failed check, while Desktop Core, four smoke shards, Mobile, Windows Rust, and one Docker build remained in progress. Both Desktop integration shards and the macOS Desktop build were green. External gate completion is not converted into author rework without a concrete defect.

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated re-review at head 318bfe3 (delta from previously cleared 4c25af1).

Verdict: CLEAR. The delta is a single test-only commit adding a reconnect middle-insertion anchoring E2E case to desktop/tests/e2e/history-transactions.spec.ts. Two independent code-review lanes converged with no findings.

What we verified at the exact head:

  • True interior insertion oracle. The test derives a gap inside retained store.pages[1], then asserts the complete prior ID sequence with exactly the injected ID spliced at that interior index — a check that cannot pass through a prepend, tail replacement, or reorder, and that pins both ends of the window.
  • The row can only arrive via window revalidation. __BUZZ_E2E_RESTART_MOCK_WEBSOCKETS__ clears the mock socket map synchronously before close delivery, and the injection happens in the same browser task, so emitMockLiveEvent has no socket to deliver through; the poll then requires membership in ChannelWindowStore.pages, which only get_channel_window publication populates.
  • Fresh verification fetch is real. The mock window endpoint honors the composite (until, before_id) keyset like the relay and snapshots the store after channelWindowDelayMs, so the persisted middle row genuinely flows through the revalidation join page rather than a cached slice.
  • Zero-drift assertion is strict. Frame-by-frame anchor tracing starts before the disconnect, rejects any missing sample, and bounds every offset within 5px; the injected row must mount above the anchor. This exercises the non-prepend Virtua path (stable keys, shift=false), closing the middle-insertion concern at the exact code path rather than via the prepend compensator.
  • Determinism. The deep-history fixture seeds one row per minute, so the floored midpoint timestamp is unique and strictly between its neighbors; ID tiebreaks cannot affect placement.

CI at this head is fully green, including all Desktop Smoke E2E shards and both E2E Integration shards, so the new test itself has executed and passed. Previously noted MINORs (pagination liveness bound, held-prepend diagnostic, unlabeled virtua fork) are unchanged by this delta and remain non-blocking.

wesbillman and others added 3 commits August 29, 2026 09:16
Bring the PR branch onto the exact claimed base with a clean mechanical merge.

Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Preserve the PR history-transaction model while integrating the current channel-history error and retry surface. Keep both sides’ projection regressions.

Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Keep exhausted recovery retries inside the notice action so retained history remains usable without an unhandled rejection.

Co-authored-by: Carl <9d00794d3df50972eb8b615511783cab12a77a8fd5dd5edd58073ec73b54bd8b@buzz.block.builderlab.xyz>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman

Copy link
Copy Markdown
Collaborator Author

Resolved the conflict with current main while preserving the history-transaction model and current channel-history error/retry behavior. The merge exposed an unhandled rejection in HistoryRefreshNotice; the follow-up now contains exhausted recovery failures while preserving loaded history and preventing failed Load latest navigation.

Validation on pushed head 55be15c74c6155af4f6def93ff3f27f19973747d: pre-push Desktop typecheck and full Desktop unit suite passed (5,862/5,862), along with the repository file-size/check hooks.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:bot: Jude’s code review agent re-reviewed exact head 55be15c74c6155af4f6def93ff3f27f19973747d against base 00e61eafa917d296104006576b7a2ddbfd58bb5a: approved. The complete systems/integration and product/UI passes found no unresolved author-actionable defect after the base reconciliation and retry-failure fix.

High-risk contracts traced

  • The authoritative channel window, projected message cache, keyed Virtua compensation, pagination reservation/receipt retirement, and settle-gated visual commit were traced across older pages, metadata/marker changes, interior insertion/deletion, backdated live rows, frozen tails, reconnect recovery, cancellation, optimistic-send rollback, and channel navigation.
  • The changed-head retry delta correctly contains an exhausted refresh rejection at the recovery control while its finally path retires the exact refresh token. Removing the catch causally restores the uncaught Error: offline failure in HistoryRefreshNotice.test.mjs; restored exact head passes all seven cases.
  • Error/recovery controls retain usable history and expose alert/status semantics, native Retry and Load latest buttons, and disabled fetching states. Browser coverage exercises actual CDP wheel input and momentum-shaped settle gating rather than only synthetic state calls.
  • Open #6601 materially overlaps channelWindowStore, older-page loading, timeline/list rendering, settle-gated prepends, and E2E coverage. This is an integration-order constraint, not a defect in this head: whichever implementation lands second needs deliberate semantic reconciliation preserving keyed compensation and input-retirement invariants, followed by fresh behavioral proof. A mechanical conflict resolution would be reckless.

Exact-head validation

  • Full Desktop unit package: 5,862 passed / 0 failed; Desktop TypeScript check and E2E production build passed.
  • Targeted history/reconnect Playwright: 26 passed / 0 failed, including deep-history reconnect, an older request in flight, true middle insertion, DM marker mutation, deletion/live metadata during prepend, Retry, Load latest, and unchanged-head recovery. A separate focused transaction run passed 8/8.
  • pnpm typecheck, pnpm build, and HistoryRefreshNotice.test.mjs 7/7 passed in the independent systems pass.
  • At submission, GitHub still reported the exact base/head and MERGEABLE. Web, macOS Desktop Build, both Desktop E2E Integration shards and aggregate, relay setup, all four Desktop Smoke shards, Semgrep, zizmor, DCO, and container builds were successful. Desktop Core remained in progress with no observed failure; that named CI gate owns merge readiness.

Findings and ownership

  • Blocking findings: none.
  • Author action: none.
  • Verification owner: CI/release gate for completion of Desktop Core; integration owner for the eventual #6601 semantic reconciliation; reviewer/tooling for native/manual-input confidence.
  • Residual risk: Chromium geometry, cache/window ordering, recovery controls, and wheel/momentum-shaped behavior are strongly covered. Physical trackpad/touchscreen input, scrollbar drag, native WKWebView/mobile rendering, broad keyboard-only operation, and manual screen-reader announcements were not independently witnessed. Those are confidence gaps, not author rework.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE
Reviewed: 00e61eafa917d296104006576b7a2ddbfd58bb5a..55be15c74c6155af4f6def93ff3f27f19973747d (exact head 55be15c74c6155af4f6def93ff3f27f19973747d)
Risk: high — virtualized history, deferred state, reconnect recovery, and cursor/window ownership can silently move or lose the reader's place.

Behavior/contracts traced: query/cache versus authoritative-window ownership; page reservation and receipt retirement; input-settle/DOM-stability admission; Virtua keyed size reconciliation and surviving-neighbor anchoring; interior insertion/deletion/marker and backdated-live mutations; reconnect cursor validation, frozen-tail buffering, recovery intent/retry/cancellation; optimistic-send rollback and reaction hydration; current-base resolution and #6601 overlap.

Findings: no unresolved author-actionable defect. The changed head correctly handles exhausted recovery refresh rejection after TanStack projects it into refreshError, while finally retires the exact token; removing that catch causes HistoryRefreshNotice.test.mjs to fail with uncaught Error: offline. Keyed Virtua compensation remains the single scroll-anchor owner, and browser evidence covers deep reconnect, older-page concurrency, middle insertion, DM markers, deletion/live metadata during prepend, Retry, Load latest, and unchanged-head recovery.

Author action: none.
Verification owner: integration owner for deliberate #6601 semantic reconciliation; native/release validation for physical trackpad/touchscreen, scrollbar drag, WKWebView, and broader keyboard/screen-reader observation.

Validation: exact-head full Desktop suite passed 5,862/5,862; TypeScript and E2E production build passed; targeted history/reconnect Playwright passed 26/26; systems lane additionally passed HistoryRefreshNotice.test.mjs 7/7 and history-transactions.spec.ts 8/8. Live GitHub head/base remained exact, the PR is mergeable/clean, and all hosted checks completed without failure.

Manual/native evidence: targeted Chromium Playwright exercised CDP wheel and momentum-shaped settle behavior. No physical-input or native WKWebView run was performed in this review.

Residual risk: #6601 substantially overlaps window storage, paging, timeline, settle semantics, and E2Es. Whichever lands second must preserve #7006 keyed itemKey compensation and input-retirement semantics while deliberately reconciling #6601; mechanical conflict resolution is unsafe. Native/physical-input behavior remains unwitnessed, owned by reviewer/release validation rather than the author.

— :bot: Jude’s code review agent

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated re-review at head 55be15c (delta from previously cleared 318bfe3): REVIEW CLEAR — no blocking findings.

Delta reviewed: two main merges plus one branch commit (55be15c, retry-failure containment in HistoryRefreshNotice.tsx).

  • Merges verified at tree level. 813b0e6's tree is byte-identical to the auto-merge of its parents. fe1732c had real conflicts in MessageTimeline.tsx and projectChannelWindow.test.mjs; the resolution preserves both parents — main's showTimelineError surface and cold-error intro suppression are carried, the branch's atomic renderedSnapshot.historyExhausted intro-start boundary replaces main's pre-transaction live/deferred inference (correct under this PR's admitted-snapshot model), and both parents' conflicted test blocks survive with no dropped test names.
  • The containment catch is correctly scoped. refreshChannelWindowMessages rejects on exhausted retries (throwOnError: true), and the query boundary writes refreshError into the window store before rethrowing — so the notice-owned handler contains a failure that is already fully represented in UI state, erases no signal, and cannot reach the onLoadLatest navigation gate. finally still retires an unclaimed refreshLatestOnly token, and the compare-and-clear cannot clobber a newer click's token.
  • Live E2E at exact head (headless, isolated relay): forced refresh failure surfaced the notice with all retained history rendered and scrollable; offline Retry and Load latest both settled with zero unhandledrejection / pageerror events, controls re-enabled, reader anchor preserved; restored-connectivity Retry cleared the notice in place and Load latest reached the new tail with the token retired.
  • CI is green across the board at this head; the skipped Rust lanes are path-correct for a TS-only delta.

One non-blocking note: the containment fix ships without a regression test that would detect the unhandled rejection it fixes — the pre-existing "exhausted retries preserve history" cases were green before the fix. A harness-level unhandledrejection listener assertion would pin this behavior; fine as a follow-up.

Two independent code lanes and the live E2E lane converged on this verdict.

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.

3 participants