Skip to content

Virtualize and harden native chat timeline#949

Draft
bkudiess wants to merge 11 commits into
openclaw:mainfrom
bkudiess:chat-virtualized-refactor
Draft

Virtualize and harden native chat timeline#949
bkudiess wants to merge 11 commits into
openclaw:mainfrom
bkudiess:chat-virtualized-refactor

Conversation

@bkudiess

@bkudiess bkudiess commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • virtualize the native chat timeline with a WinUI ItemsRepeater host while preserving the existing chat visual design
  • split chat timeline/composer internals into clearer UI-focused names and helper files
  • harden chat scroll behavior: default to latest on open, preserve intentional scrolled-up position, stabilize follow-bottom/load-earlier behavior
  • restore Allow always permission action rendering and AllowedAlways decided badge handling
  • render unknown permission action keys explicitly as Action: <key> instead of falling through to Allow
  • update the native chat UI proof test for the new VirtualizedChatView/ItemsRepeater path

Validation proof

Validated locally on chat-virtualized-refactor after the latest push:

./build.ps1
  PASS - all projects built (Shared, Cli, WinNodeCli, SetupEngine, WinUI)

dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restore
  PASS - 2,722 passed, 31 skipped

dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore
  PASS - 1,654 passed

dotnet test ./tests/OpenClawTray.FunctionalUI.Tests/OpenClawTray.FunctionalUI.Tests.csproj --no-restore
  PASS - 10 passed

Additional focused proof:

dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore --filter "ChatPermissionRenderingContractTests|OpenClawChatDataProviderTests.RespondToPermissionAsync_AllowAlways|StableRowCollectionTests|ChatToolCallsToggleContractTests|ChatTimelineVirtualizationContractTests"
  PASS - focused permission/virtualization contracts passed

Manual / computer-use proof

  • Launched the rebased branch build locally and opened openclaw://chat.
  • Computer-use confirmed the OpenClaw Companion Chat surface is visible and targetable.
  • Confirmed Chat opens on the latest visible message area with the Scroll-to-latest affordance hidden when already following latest.
  • Navigated away to Connection and back to Chat; Chat returned to latest when no intentional scrolled-up offset was saved.
  • Verified the branch keeps the existing visual design while the timeline now uses the native VirtualizedChatView host.

UI proof note

  • ChatTimelineVirtualizationProofTests was updated to validate the new native VirtualizedChatView/ItemsRepeater path, including the chrome row and native-host realization expectations.
  • Local direct UITest execution is blocked on this machine by Windows App SDK dynamic dependency resolution (Package dependency criteria could not be resolved), so CI remains the source of truth for the UITest job.

Notes

  • Unrelated WorkspacePage work was kept out of this branch and preserved only in local stashes.

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 7:30 PM ET / 23:30 UTC.

Summary
The branch replaces the native chat timeline with a WinUI VirtualizedChatView/ItemsRepeater host, adds FunctionalUI native-control hosting, renames chat UI components, hardens scroll and permission rendering, updates localization, and adjusts chat tests.

Reproducibility: not applicable. as a PR: this is a native chat UI refactor/performance hardening change, not a standalone bug report. Source inspection, the PR body, and current-head checks identify the affected timeline, scroll, and permission paths.

Review metrics: 3 noteworthy metrics.

  • Diff size: 29 files, +1,406/-736. The PR spans native chat, FunctionalUI hosting, localization, and tests, so maintainers should review the final behavior as a broad UI refactor.
  • Final response delta: 7 files, +30/-1 since requested-changes review. The latest commit is a focused response to the permission-label blocker rather than another large refactor.
  • Current-head checks: 8 passing, 4 skipped. The earlier pending exact-head test concern is now cleared, leaving maintainer review and proof acceptance as the main gate.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Resolve or dismiss the outstanding requested-changes review after final-head verification.
  • Take the PR out of draft only when the maintainer is satisfied with the native chat scroll/session-state proof.

Risk before merge

  • [P1] The new VirtualizedChatView owns per-session scroll offsets, follow-bottom, load-earlier, and restoration behavior; a regression could stale or mis-associate a user's intentional chat position.
  • [P1] The latest head fixes the concrete permission-action label blocker and CI is green, but the PR remains draft with an outstanding requested-changes review that should be resolved by a human before merge.

Maintainer options:

  1. Verify final native chat state before merge (recommended)
    Maintain the draft until final-head proof covers selected-session, intentional scrolled-up, scroll-to-latest, load-earlier, and streaming follow-bottom behavior.
  2. Keep draft if proof is still thin
    If maintainers are not satisfied with the current proof package, keep the PR open for a narrow proof update rather than merging the session-state change.

Next step before merge

  • [P2] Human review is needed because the PR is draft, collaborator-authored, has an outstanding requested-changes review, and carries session-state merge risk rather than a narrow automated repair task.

Maintainer decision needed

  • Question: Should this draft PR move toward merge after final-head native chat scroll/session-state proof is accepted and the outstanding requested-changes review is resolved?
  • Rationale: The patch is a broad native chat host migration with session-state risk, and the live PR still has draft plus requested-changes state that cleanup automation should not override.
  • Likely owner: shanselman — shanselman authored the latest requested-changes review and has baseline history in the current native chat/FunctionalUI surface.
  • Options:
    • Verify final head, then land (recommended): Confirm open-at-latest, scrolled-up preservation, load-earlier anchoring, follow-bottom streaming, and permission actions on the current head, then resolve the review and merge.
    • Keep draft for more proof: Leave the PR draft if maintainers want visible proof beyond the PR body's copied validation and manual/computer-use notes.
    • Split the refactor: Ask for a narrower branch if the native host migration is too large to review as one session-state change.

Security
Cleared: No concrete security or supply-chain regression was found; the final head improves the security-sensitive approval UI label for unknown actions and does not add dependencies, workflows, scripts, or secret handling.

Review details

Best possible solution:

Resolve the requested-changes review on the current head after maintainers confirm the native chat scroll/session-state proof, then land or keep the draft for a targeted follow-up.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a PR: this is a native chat UI refactor/performance hardening change, not a standalone bug report. Source inspection, the PR body, and current-head checks identify the affected timeline, scroll, and permission paths.

Is this the best way to solve the issue?

Yes, subject to maintainer merge decision: the final delta fixes the requested permission label bug narrowly, and the native-host approach has targeted contract/UI proof tests. The remaining concern is manual acceptance of broad chat scroll/session-state behavior.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against c8cd9869d828.

Label changes

Label justifications:

  • P2: This is a normal-priority native chat performance and hardening PR with meaningful but bounded UI/session-state blast radius.
  • merge-risk: 🚨 session-state: Merging this PR moves chat scroll offset, follow-latest, load-earlier, and restoration ownership into a new native host.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes copied local build/test output plus manual/computer-use proof for opening openclaw://chat, latest-message behavior, navigation return, and the native VirtualizedChatView host; the current PR also carries proof: sufficient.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied local build/test output plus manual/computer-use proof for opening openclaw://chat, latest-message behavior, navigation return, and the native VirtualizedChatView host; the current PR also carries proof: sufficient.
Evidence reviewed

What I checked:

Likely related people:

  • TurboTheTurtle: Git history and GitHub commit metadata tie the nearest merged timeline virtualization work to commit fcc7477, which this PR replaces with a stronger native host. (role: recent chat virtualization contributor; confidence: high; commits: fcc74778a35c; files: src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs, src/OpenClawTray.FunctionalUI/FunctionalUI.cs)
  • calebeden: Recent merged chat timeline/root work added queued chat UI and fixed render identity in the same native chat surface. (role: recent chat UI and render-state contributor; confidence: high; commits: c9b5476a873f, f89a88a6baf4, 02f2421a5e75; files: src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs, src/OpenClaw.Tray.WinUI/Chat/OpenClawChatRoot.cs, src/OpenClaw.Tray.WinUI/Chat/OpenClawComposer.cs)
  • shanselman: Blame attributes the current main baseline around the old timeline host to commit 4166e0f, and the latest human review requested changes on this PR. (role: reviewer and baseline contributor; confidence: high; commits: 4166e0fd63f8; files: src/OpenClaw.Tray.WinUI/Chat/OpenClawChatTimeline.cs, src/OpenClawTray.FunctionalUI/FunctionalUI.cs)
  • bkudiess: GitHub commit metadata ties the final permission-label fix to bkudiess, and current main has adjacent WinUI/localization commits by the same contributor. (role: current branch owner and adjacent WinUI contributor; confidence: medium; commits: aee6c677736b, c3371d66f72d, cc2834c1a422; files: src/OpenClaw.Tray.WinUI/Chat/ChatTimeline.cs, src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (5 earlier review cycles)
  • reviewed 2026-07-09T01:54:34.407Z sha a5f40be :: needs changes before merge. :: [P2] Update the native timeline proof assertions
  • reviewed 2026-07-09T02:19:32.425Z sha 6ac0da0 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-09T15:36:05.723Z sha 570d8ef :: needs maintainer review before merge. :: none
  • reviewed 2026-07-09T15:43:31.148Z sha 570d8ef :: needs maintainer review before merge. :: none
  • reviewed 2026-07-09T19:37:14.620Z sha 3629e1b :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal priority bug or improvement with limited blast radius. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 9, 2026
@bkudiess bkudiess marked this pull request as ready for review July 9, 2026 15:27
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 session-state 🚨 Merging this PR could lose, corrupt, stale, or mis-associate session or agent state. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 9, 2026
bkudiess and others added 10 commits July 9, 2026 12:22
Add a clean-room virtualized chat timeline host backed by ItemsRepeater, preserve the existing chat visuals, and introduce the FunctionalUI native-control boundary needed to host native surfaces safely.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Split timeline and composer helpers into focused files, add a tested stable row-source synchronizer, and keep virtualization updates incremental without changing chat visuals.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Address final dual-review hardening items by removing per-render entry-id set allocation, stabilizing the thinking row key, locking session offset storage, preserving row host contexts across remounts, and reapplying prepend correction until virtualized extents stabilize.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Drop redundant OpenClaw prefixes from chat UI component and file names, and track realized virtualized rows explicitly instead of relying on ItemsRepeater parent semantics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rebase the chat virtualization changes onto latest main, restore the extracted timeline helper, preserve synchronous first row measurement, and replace the recursive bottom chase with a single-shot ScrollViewer state machine that has fallback completion.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the chat virtualization branch scoped to chat changes; the WorkspacePage work remains preserved in the local stash.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep Chat opening at latest unless the user intentionally left it scrolled up, restore timeline helper contracts after rebasing onto latest main, and use a single-shot bring-into-view state machine with synchronous first row measurement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Render all gateway-provided permission actions, map AllowedAlways decisions to the correct label, and add contract coverage for the Allow always action and badge.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adjust the UI proof test to validate the native VirtualizedChatView ItemsRepeater path, including the chrome spacer row and native-host realization metrics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Update the native timeline proof assertions, restore Allow always rendering, and keep chat-open scroll behavior aligned with the latest-row policy.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bkudiess bkudiess force-pushed the chat-virtualized-refactor branch from 570d8ef to 3629e1b Compare July 9, 2026 19:30

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

Thanks for pushing this forward — this is a big and valuable direction. Moving the native chat timeline to an ItemsRepeater/VirtualizedChatView path is the right kind of work for long conversations, and I appreciate that the PR keeps the existing visual design while adding tests around row identity, StableRowCollection, permission rendering, and the virtualization proof path.

I did a dual-model adversarial pass plus my own inspection. The broad architecture looks promising, but I do not think this is merge-ready yet. There is one concrete approval-label bug, and the exact-head test job is still pending, which matters a lot for a PR that touches the chat renderer and FunctionalUI native hosting.

Blocking before merge

Unknown permission actions render visually as "Allow"

In ChatTimeline.cs, pending permission actions are normalized and rendered like this:

var label = action switch
{
    ChatPermissionActionKeys.AllowAlways => allowAlwaysLabel,
    ChatPermissionActionKeys.Deny => denyLabel,
    _ => allowLabel,
};

var button = Button(label, () => onResponse?.Invoke(requestId, action))

That means any future/non-standard gateway action key is visually shown to the user as Allow, while the click sends the original unknown action key. Because this UI is a security/approval surface, the label must describe the action being submitted. A user should never click a button labeled "Allow" and actually send an unknown action.

Suggested fix:

  • Keep the explicit labels for known actions:
    • allow / allow-once → "Allow once"
    • allow-always → "Always allow"
    • deny → "Deny once" or the existing deny copy
  • For unknown actions, render a safe explicit fallback rather than allowLabel. Examples:
    • use a humanized action key: Action: <key>
    • or a localized format: Chat_Permission_ActionFallbackFormat = "Run action: {0}"
  • Add a regression test that proves an unknown action key does not render as "Allow" but still invokes the original action key if clicked.

This should block merge.

Exact-head test check is still pending

At review time, gh pr checks 949 still showed the Build and Test test job pending. This PR changes:

  • native chat rendering,
  • FunctionalUI native host behavior,
  • virtualization / realization,
  • scroll-to-latest behavior,
  • permission rendering,
  • and UITest proof expectations.

For this kind of change, the test job is not just routine. It is the primary behavior proof for Tray tests, FunctionalUI tests, and the virtualization UI proof path. Please wait for it to finish green or rerun it if stuck.

Additional validation I would like before merge

Once the blocker above is fixed and CI is green, please include current-head proof for these specific behaviors:

  1. Open at latest

    • Open Chat with a non-empty history.
    • Confirm the visible timeline starts at the latest message and the scroll-to-latest affordance is hidden when already following latest.
  2. Preserve intentional scrolled-up position

    • Scroll up intentionally.
    • Navigate away and back, or otherwise force a remount if that is part of the intended contract.
    • Confirm the scrolled-up position is preserved when it should be.
  3. Load earlier / prepend anchoring

    • Trigger the load-earlier path.
    • Confirm prepended rows do not yank the user to the top or bottom unexpectedly.
  4. Follow-bottom during streaming

    • While following latest, stream/update an assistant response.
    • Confirm the viewport follows smoothly and the scroll-to-latest button does not flash or incorrectly appear during programmatic animated scrolling.
  5. Permission actions

    • Confirm Allow once, Always allow, and Deny render correctly.
    • Confirm the decided badge for AllowedAlways renders as intended.
    • Include the new unknown-action fallback test mentioned above.

Non-blocking notes

FunctionalUI native host design looks mostly right

The NativeElement/ConfigureNative path appears to respect the existing FunctionalUI mark-and-sweep lifecycle because the native host itself is still created through the normal GetOrCreate<ContentControl>(path) path and therefore gets visited during the eager root render. The virtualization is then inside the hosted native control, and each realized row owns its own host/render path. That is the right pattern for adding virtualization without fighting the renderer's prune model.

Please keep this invariant in mind: lazy/virtualized controls must keep the owner host visited every render, and any realized row host needs an explicit cleanup path. The current direction seems aligned with that.

Re-mounting realized rows on every update may be acceptable but deserves attention

RefreshRealizedRows appears to refresh all realized rows whenever the backing row map changes. Because virtualization bounds the realized set, this is probably okay, and FunctionalUI diffing should make it tolerable. Still, streaming assistant text can update frequently, so please keep an eye on whether token streaming causes visible row churn or unnecessary work.

Source-text tests are useful but not sufficient

Several tests are source-contract tests that assert implementation shape. That is helpful for guarding refactors in WinUI-only seams, but the merge confidence for this PR should come from runtime behavior: FunctionalUI tests, Tray tests, and the UI virtualization proof tests. Please do not treat source-text assertions alone as proof that scrolling/realization behavior works.

Suggested done criteria

I would be comfortable re-reviewing once:

  • unknown permission actions no longer render as "Allow";
  • a regression test covers that behavior;
  • the exact-head test job is green;
  • PR proof explicitly covers open-at-latest, scrolled-up preservation, load-earlier anchoring, follow-bottom during streaming, and permission action rendering.

Again, the overall direction is good. I just want to be careful because this PR changes the core chat rendering surface and an approval UI path.

Avoid showing unknown gateway permission action keys as Allow, add localized fallback copy, and cover the security-sensitive label behavior with a contract test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bkudiess

bkudiess commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed Scott's blocking permission-action feedback: unknown gateway permission actions now render with an explicit localized fallback label (\Action: ) instead of \Allow, while still submitting the original action key. Added contract coverage for the fallback, and full local validation is green (build, Shared, Tray, FunctionalUI).

@bkudiess bkudiess marked this pull request as draft July 9, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 session-state 🚨 Merging this PR could lose, corrupt, stale, or mis-associate session or agent state. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants