Skip to content

fix(chat): keep empty soft-swap centered until first turn - #140

Merged
Tomlord1122 merged 3 commits into
Cometline:mainfrom
tomtom-bot7:fix/soft-swap-composer-dock-race
Sep 11, 2026
Merged

Tomlord1122 merged 3 commits into
Cometline:mainfrom
tomtom-bot7:fix/soft-swap-composer-dock-race

Conversation

@tomtom-bot7

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #139: after /change, mid-switch visibility could still dock an empty fork before remount reset finished, so the first-message fly-in lost hero origins.

  • Reset session flight/composer flags in $effect.pre (before syncComposerPhase)
  • Mid-switch: known-empty cache (getCachedItemCount === 0) is not visible
  • syncComposerPhase: empty + not awaiting → force center (emptiness wins)

Product rule: empty session stays centered; dock only once there is real content (or first-turn prepare).

Test plan

  • New chat → /change → composer stays centered (no center→dock)
  • First message after that runs FirstTurnFlight / hero→dock as expected
  • Session with messages still docks on soft switch
  • vitest conversation-controller (incl. empty+visible→center)

Reviewed two-axis by tomtom.bot40 @ 24dfd1b.

After /change, mid-switch visibility could still dock the composer
before remount reset finished, killing first-message flight origins.
Prefer cache emptiness in syncComposerPhase, treat known-empty mid-
switch as not visible, and reset session flight flags in $effect.pre.

@tomtom-bot40 tomtom-bot40 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Standards

Tight follow-up to #139. $effect.pre + emptiness-wins in syncComposerPhase are clear and well-commented. No blocking smells.

Spec

Matches the post-#139 Spec:

  1. Remount reset runs in $effect.pre so it wins the race against mid-switch syncComposerPhase dock
  2. Mid-switch known-empty (getCachedItemCount === 0) is not treated as visible
  3. Empty + !awaiting → force center (emptiness beats stale hasVisibleConversation)
  4. Empty session stays centered; content docks

Pre-PR two-axis sign-off stands.

Standards: pass · Spec: pass

/change AppendSystemMessage becomes a status row; raw item count made
empty forks look non-empty, docking the composer and skipping
FirstTurnFlight. Gate first-turn and composer phase on user/assistant
turns via hasCachedConversationTurns.

@tomtom-bot40 tomtom-bot40 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review: 39023d9 ignore fork status for first-turn dock

Spec — pass

Validated remaining center→dock: fork AppendSystemMessagestatus ChatItem → raw count > 0 killed firstTurn. This commit gates firstTurn / bindSession / syncComposerPhase / soft-swap remount on hasCachedConversationTurns (user|assistant only). Status-only fork stays centered + FirstTurnFlight. Test covers it.

Standards — pass

Clear helper + comments. Non-blocking residual: when store is bound, hasVisibleConversation still uses items.length > 0 (status can hide EmptyChatState while composer stays centered) — acceptable for this fix.

Together with 24dfd1b, #140 Spec is complete for the user’s remaining repro.

Standards: pass · Spec: pass

svelte-check requires TranscriptResponse.session_id; CI failed on the
fork status-only controller test mocks.

@Tomlord1122 Tomlord1122 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.

LGTM

@Tomlord1122
Tomlord1122 merged commit 32a1375 into Cometline:main Sep 11, 2026
1 check passed

@tomtom-bot40 tomtom-bot40 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review: d1a43aa EmptyChatState on status-only fork

Spec — pass

Closes the residual: bound-session hasVisibleConversation now uses hasCachedConversationTurns (and snapshot user|assistant), so fork status notes no longer unmount EmptyChatState/avatar while composer stays centered.

Standards — pass

One predicate end-to-end with dock/firstTurn. Clean.

Standards: pass · Spec: pass · tip signed off

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