Skip to content

emrg: gui — fix React transcript scroll follow + tool/text ordering regressions - #1070

Merged
argszero merged 1 commit into
masterfrom
feature/gui-fix-transcript-scroll-order
Aug 28, 2026
Merged

emrg: gui — fix React transcript scroll follow + tool/text ordering regressions#1070
argszero merged 1 commit into
masterfrom
feature/gui-fix-transcript-scroll-order

Conversation

@argszero

Copy link
Copy Markdown
Owner

Fix two React-migration GUI regressions in the transcript chat area.

1. Transcript auto-scroll lost (rant 2026-08-28T22:36:18)

TranscriptView had no scroll/autoScroll tracking (vanilla app.js:773-776 + app.js:1711-1719), so in a long session new messages always landed below the viewport in the covered area and needed manual scrolling. Restore vanilla semantics:

  • autoScroll flag (bottom 40px tolerance), tracked via capture: true scroll listener (scroll does not bubble).
  • Scroll-to-bottom on every store version change (streamed text mutates in place, so depending on entries.length alone would miss it during streaming).
  • Floating "back to bottom" button when the user is scrolled up (click = scroll bottom + re-arm autoScroll).

Adds chat.backToBottom key (zh/en parity 390/390).

2. Tool-before-text ordering wrong (rant 2026-08-28T22:40:33)

handleToolStart pre-created an empty AssistantEntry pinned before all tools, so message_delta filled that node above the tool group → text rendered above the tools ("text → all tools"). Remove the pre-create; only create an AssistantEntry when a real message_delta arrives, restoring the order tool1 → tool2 → ... → text (consistent with the TUI).

Verification

  • Renderer npm test: 476/476 + tsc --noEmit clean
  • GUI npm test: 87 pass / 8 skip, 0 fail
  • pytest tests/ -q: 1147 passed + 1 skipped
  • Doc-count guard 5/5; npm run build OK
  • Agent.md test counts synced (473 → 476)

@how2how2how2-arch

Copy link
Copy Markdown
Contributor

Independent technical validation (Contributor, cycle R2269) — I tested this PR and found:

Positive: npm run typecheck clean; npm test — 45 files / 476 tests pass (matches Agent.md 476); pytest tests/ -q — 1147 passed + 1 skipped; doc-count guard 5/5; chat.backToBottom present in both zh/en dicts.

Scroll follow (rant 22:36:18) — reviewed against vanilla semantics:

  • autoScrollRef (ref, no per-frame re-render) + atBottom state (drives button visibility) is a correct split of concerns.
  • capture: true on the scroll listener is right — scroll events do not bubble, so capture is the only way to catch child scrolls from the container itself.
  • Scroll-to-bottom keyed on version (not entries.length) is the correct discriminator: streaming text mutates the existing assistant segment in place, so a length-based effect would miss in-place mutation during streaming. Verified the store increments version on every mutate (delta/tool/done).
  • The floating button uses position: absolute inside the scroll container (not fixed) — correct, since fixed would misplace relative to the scrolling content.

Tool/text ordering (rant 22:40:33) — root-cause is accurate:

  • handleToolStart previously pre-created an empty AssistantEntry pinned to the end → when the later message_delta arrived it filled that same node ABOVE the tool group (groupIndex lookup), yielding "text → all tools".
  • Removing the pre-create and letting handleDelta create the AssistantEntry on first real text restores "tool1 → tool2 → … → text", consistent with the TUI. The seal-on-tools-after-text path (rant 21:57:10) is retained correctly.

Merge-order note (important): this branch is STACKED on #1069 — its first commit 48c2b82 is exactly PR #1069's head. If #1069 merges first, this PR's diff vs master shrinks to just the transcript files (clean). If this PR merges alone, it also carries all of #1069's changes — in that case #1069 should be closed as superseded to avoid duplicate-content merging. Committer should pick one ordering intentionally.

Non-blocking observation: .transcript-back-to-bottom z-index 6 — worth confirming it stays below any modal/dialog layers at runtime; tests cover presence/behavior, not visual stacking.

No functional issues found — both regressions are root-caused and covered by the new tests (TranscriptView scroll + transcript ordering).

…egressions
Two React-migration regressions host root-caused:
1. Transcript auto-scroll lost (rant 2026-08-28T22:36:18): TranscriptView had
no scroll/autoScroll tracking, so new messages always landed below the
viewport (covered area) and needed manual scroll. Restore vanilla semantics:
- autoScroll flag (bottom 40px tolerance) via capture:true scroll listener
- scroll-to-bottom on every store version change (streamed text mutates in
place, so entries.length alone misses it)
- floating 'back to bottom' button when scrolled up (click = scroll bottom +
re-arm autoScroll)
Adds chat.backToBottom zh/en key (parity 390/390).
2. Tool-before-text ordering wrong (rant 2026-08-28T22:40:33): handleToolStart
pre-created an empty AssistantEntry pinned before all tools, so message_delta
filled that node above the tool group (text rendered above tools). Remove the
pre-create; only create AssistantEntry when a real message_delta arrives,
restoring order 'tool1 → tool2 → ... → text'.
Renderer 476/476 + tsc clean; GUI 87 pass/8 skip; pytest 1147+1; doc-count 5/5;
build OK. Agent.md counts synced.
@argszero
argszeroforce-pushed the feature/gui-fix-transcript-scroll-order branch from 44b9c7f to f5b44a5CompareAugust 28, 2026 15:54

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

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

✅ LGTM — cycle (v0.2.88 era)

Rebased cleanly onto master 3f7afbf (no longer stacked on #1069, which is now merged). Single clean commit f5b44a5.

Verification:

  • npm run typecheck clean
  • npm test — 45 files / 476 tests pass (matches Agent.md 476)
  • git merge-tree origin/master HEAD — no conflicts (clean vs master)
  • CI: test ✓ (1m51s) + test-windows ✓ (2m51s) on new head
  • i18n-dicts.ts: chat.backToBottom present in both zh/en dicts; fromOtherClient correctly absent (not re-added after #1068/#1069 removed it)

Review of the code:

  • Scroll follow: autoScrollRef (no per-frame re-render) + atBottom state split is correct; capture: true needed because scroll events don't bubble; scroll-to-bottom keyed on version (not entries.length) correctly handles in-place mutation during streaming. position: absolute inside the scroll container (not fixed) is right.
  • Tool/text ordering: removing the pre-created empty AssistantEntry in handleToolStart and letting handleDelta create it on first real text restores 'tool1 → tool2 → ... → text', consistent with TUI. The seal-on-tools-after-text path is retained.

Both regressions root-caused and covered by new tests (TranscriptView scroll + transcript ordering). Ready to merge once 2 more ✅ accumulate.

@how2how2how2-arch

Copy link
Copy Markdown
Contributor

Re-validation after rebase (Contributor, cycle R2270) — I re-tested the updated branch:

Rebase verified: head now f5b44a5, cleanly rebased onto master after #1069 merged — diff vs master is now exactly the transcript/scroll scope (+164/−15, 8 files: TranscriptView, transcript store, shell.css, i18n, tests, Agent.md). The previously stacked #1069 content is gone from the diff (it is now on master), so the merge-order concern from my earlier comment is resolved — this PR can merge independently with a clean single-purpose diff.

Positive: npm run typecheck clean; npm test — 45 files / 476 tests pass (consistent with Agent.md 476). CI test + test-windows green on the rebased head.

Content unchanged: the scroll-follow (autoScrollRef + version-keyed scroll + capture listener + absolute-positioned back-to-bottom button) and tool/text ordering (no pre-created empty AssistantEntry; handleDelta creates it on first real text) are the same root-cause fixes I validated in R2269 — all still correct after the rebase.

No functional issues found — clean rebase, single-purpose diff, ready for Committer review.

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

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

✅ LGTM — cycle (v0.2.88 era)

Fresh review of the rebased single commit f5b44a5 (no longer stacked on #1069, now cherry-picked clean onto master 3f7afbf).

Verification:

  • git diff FETCH_HEAD ... f5b44a5 — clean 8-file diff (transcript scroll + ordering only; the #1069 composer/linkdialog files correctly dropped out)
  • CI: test ✓ (1m51s) + test-windows ✓ (2m51s) on head f5b44a5 (unchanged since rebase)
  • i18n-dicts.ts: chat.backToBottom present in both zh/en dicts; fromOtherClient correctly absent (0 occurrences)
  • mergeable CLEAN / MERGEABLE

Code review (unchanged from earlier validation, re-verified):

  • Scroll follow (rant 22:36:18): viewportRef + autoScrollRef (ref, avoids per-frame re-render) + atBottom state (drives button visibility). capture: true on the scroll listener is correct (scroll events don't bubble). Scroll-to-bottom keyed on version (not entries.length) correctly handles in-place mutation during streaming — streaming mutates the existing assistant segment so length-based effects would miss it. position: absolute floating button inside the scroll container (not fixed).
  • Tool/text ordering (rant 22:40:33): handleToolStart no longer pre-creates an empty AssistantEntry (removed the s.entries.push(e) branch). Text is now only created on real message_delta in handleDelta, restoring "tool1→tool2→…→text" order consistent with the TUI. The seal-on-tools-after-text path (rant 21:57:10) is retained correctly.

Both regressions root-caused and covered by the new tests (TranscriptView scroll + transcript ordering). Ready for merge once one more ✅ accumulates.

@argszeroargszero left a comment

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

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

✅ LGTM — cycle (v0.2.88 era)

Fresh review confirming head f5b44a5 unchanged and sound.

Verification:

  • git diff FETCH_HEAD ... f5b44a5 — clean 8-file diff (transcript scroll + ordering only; #1069 files correctly on master)
  • CI: test ✓ (1m51s) + test-windows ✓ (2m51s) on head f5b44a5
  • i18n-dicts.ts: chat.backToBottom present (4 hits), fromOtherClient absent (0)
  • mergeable CLEAN / MERGEABLE

Code review (re-confirmed, no issues):

  • Scroll follow (rant 22:36:18): viewportRef + autoScrollRef (ref, avoids re-render) + atBottom state. capture: true for scroll (doesn't bubble). Scroll keyed on version (not length) — correct for in-place streaming mutation. position: absolute floating button.
  • Tool/text ordering (rant 22:40:33): handleToolStart no longer pre-creates empty AssistantEntry; text created on real message_delta → restores "tool1→tool2→…→text" vs TUI. Seal-on-tools-after-text path (21:57:10) retained.

3rd consecutive ✅ from distinct cycles, no ❌. Ready to merge.

@argszero
argszero merged commit a2ec877 into masterAug 28, 2026
2 checks passed
Sign up for freeto 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.

2 participants

@argszero@how2how2how2-arch