Skip to content

fix(app): reconverge session load with upstream to fix deep-link race#6

Closed
maschwenk wants to merge 1 commit into
devfrom
forge-session-race-close-to-source
Closed

fix(app): reconverge session load with upstream to fix deep-link race#6
maschwenk wants to merge 1 commit into
devfrom
forge-session-race-close-to-source

Conversation

@maschwenk

Copy link
Copy Markdown

What

Fixes the Forge deep-link blank-chat race (direct /session/:id mount) by reconverging the session-load path with upstream/dev.

Our fork branched from upstream before upstream added parent-message hydration to loadMessages — the step that backfills the user-message parents of the newest assistant messages so the initial limit=2 page is renderable. Our fork papered over the gap with a 5-attempt retry loop in the timeline model + a simplified ready check. When a fast background limit=200 prefetch won the shared inflight / meta.loading locks, the throttled limit=2 load got deduped/no-oped, the retry loop burned out, and data.message[id] (the only thing the timeline renders from) never got set → permanently blank transcript.

Changes

  • context/server-session.ts — restore upstream's parent-hydration in loadMessages + sessionNotFoundError.
  • pages/session/timeline/model.ts — restore upstream's isTimelineReady + plain sync(id) resource; drop the 5-attempt retry-loop hack. Now identical to upstream.
  • utils/server-errors.ts — restore sessionNotFoundError / isLocalSessionNotFoundError. Now identical to upstream.

The only remaining divergence from upstream: release meta.loading when the finishing load still owns the slot (owns), since upstream still gates that solely on the generation and can wedge loading=true forever after a generation change. ~8 lines.

Tests

  • New regression test in server-session.test.ts: reversed-order race — a fast limit=200 prefetch lands before the slow initial limit=2 load; asserts the transcript stays populated.
  • Pulled in upstream's parent-hydration + isTimelineReady coverage.
  • bun test in packages/app: 230 pass across context + timeline dirs.

Consumed by

owner/Owner#47224 bumps the apps/forge-ui/vendor/opencode submodule pin to this commit.

Realign server-session loadMessages, timeline model, and server-errors
to upstream/dev so the initial limit=2 page backfills its user-message
parents (upstream's parent-hydration). This is what makes the small
deep-link load sufficient; our fork had branched before upstream added
it and papered over the gap with a fragile 5-attempt retry loop and a
simplified readiness check, which lost the race when a fast limit=200
prefetch resolved before a throttled limit=2 initial load.

Drop those hacks (retry loop, ready simplification, inline not-found
error) and keep only the one still-needed divergence: release the
meta.loading flag when the finishing load still owns the slot, since
upstream still gates that solely on the generation and can wedge
loading=true forever.

Adds a regression test for the reversed-order race (prefetch resolves
before the slow initial load) plus upstream's parent-hydration and
isTimelineReady coverage.
@maschwenk

Copy link
Copy Markdown
Author

Superseded by #7 (cherry-pick approach instead of full reconvergence).

@maschwenk maschwenk closed this Jul 9, 2026
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