Skip to content

fix: prevent resolved clarification render loops - #361

Merged
pedronauck merged 1 commit into
mainfrom
issue-360
Aug 12, 2026
Merged

pedronauck merged 1 commit into
mainfrom
issue-360

Conversation

@pedronauck

@pedronauck pedronauck commented Aug 12, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Prevent session transcripts with resolved structured clarification events from entering React's infinite-render failure path.
  • Keep timeline rows as a pure render derivation and restrict semantic row equality to memoized child rendering.
  • Add a regression that reproduces the unstable payload identity reported in [Bug][v0.3.0-beta.13] Session thread crashes with React #301 #360 and proves later transcript content still renders.

Root cause

v0.3.0-beta.13 stored derived timeline rows in local React state and called setStableRows() during render whenever computeStableSessionRows() returned a different state object. A resolved data-compozy-event clarification can expose a new structured payload identity on each read, so the comparison never converges. Every render scheduled another render until React stopped the loop with error #301.

Current main had already removed the render-phase setter incidentally in #354, but the stateful stabilization implementation, its implementation-detail tests, and stale documentation remained. That left the failure unguarded and made the unsafe mechanism easy to reintroduce.

Changes

  • Regression coverage: add a SessionThread integration case with a resolved clarification whose structured payload has deliberately unstable identity. The test asserts the receipt, answer, and following transcript message render without entering the thread error boundary.
  • Timeline architecture: remove StableSessionRowsState, EMPTY_STABLE_SESSION_ROWS, and computeStableSessionRows; rename the remaining module to session-row-equality.ts and keep sessionRowEqual only as the memo comparator for row children.
  • Test ownership: remove pure-logic tests that froze the deleted state container's reference behavior. The user-visible render invariant now lives in the canonical component integration suite.
  • Internal docs: update the session redesign spec, QA journey, and automation backlog to describe semantic row equality and mounted-DOM stability instead of cross-render object identity.

Compozy Impact Audit

  • Native tools: no impact — checked compozy__* IDs, toolsets, descriptors, schemas, digests, risk flags, diagnostics, and capability gates; this is confined to the Web transcript renderer.
  • Extensibility and hooks: no impact — no extension, hook, skill/capability, tool/resource, registry, bridge SDK, MCP sidecar, or config lifecycle contract changed.
  • Workspace data isolation: no impact — session transcript ownership and workspace_id propagation through CLI/HTTP/UDS/core/store/Web/SSE/cache/events are unchanged; the change only removes local derived render state.
  • Official Compozy skill: no impact — no public behavior, tool ID, CLI path, hook event, capability, extension resource, or memory/network/task semantic changed.
  • Web/Docs: Web regression coverage and internal architecture references updated; no packages/site documentation impact.
  • Settings: no impact — no config.toml key or settings attachment references the removed render-state implementation.

Release Notes

🐛 Bug Fixes

QA

No scenario was added or reset because the production behavior on current main already uses pure derivation; this PR locks that behavior with a regression and removes the obsolete state mechanism. The existing clarification round-trip remains owned by docs/qa/scenarios/RT-session-clarification-roundtrip.md.

Test plan

  • Red/green mutation proof: the regression fails with the exact beta.13 render-phase state loop (Too many re-renders, AssistantMessageTimeline, thread error boundary) and passes after restoring pure derivation.
  • Focused component and timeline suites: 84 tests passed.
  • make gate: Web lint, typecheck, and full Web tests passed; fingerprint 85ba1fc2414f13df5fad9c4b912ed65be3570202.
  • React Doctor changed-scope scan: 100/100, no issues.
  • make gate-full: delegated to CI by maintainer direction; the local run was intentionally interrupted rather than reported as passing.

Closes #360

Summary by CodeRabbit

  • Bug Fixes
    • Improved timeline rendering for resolved clarifications with changing structured data.
    • Ensured resolved receipts, selected answers, and subsequent assistant messages render correctly without triggering an error boundary.
  • Performance
    • Refined row comparison for more reliable memoized rendering and live timeline updates.
  • Tests
    • Added regression coverage for volatile clarification payloads.
    • Updated streaming rendering tests to validate semantic row equality and nested updates.

Remove the orphaned render-state stabilization path, keep semantic row equality scoped to memoized rendering, and add a regression for volatile resolved clarification payloads.

Refs: #360
@vercel

vercel Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
compozy-site Ready Ready Preview Aug 12, 2026 9:22pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 9a88675.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 88734931-cc34-477f-af16-b43f2cee1f94

📥 Commits

Reviewing files that changed from the base of the PR and between 26f7b48 and 9a88675.

⛔ Files ignored due to path filters (3)
  • docs/design/opendesign/_done/session/SESSION-REDESIGN-SPEC.md is excluded by !docs/design/**/*, !**/*.md
  • docs/qa/automation-backlog/tool-call-a11y.md is excluded by !**/*.md
  • docs/qa/journeys/J-14-read-a-finished-transcript.md is excluded by !**/*.md
📒 Files selected for processing (4)
  • web/src/components/assistant-ui/__tests__/session-thread.test.tsx
  • web/src/components/assistant-ui/__tests__/session-timeline.logic.test.ts
  • web/src/components/assistant-ui/session-row-equality.ts
  • web/src/components/assistant-ui/session-timeline.logic.ts
💤 Files with no reviewable changes (1)
  • web/src/components/assistant-ui/tests/session-timeline.logic.test.ts

Walkthrough

The session timeline no longer maintains structurally shared row state. It uses semantic row equality for memoized rendering. Tests cover resolved clarification payloads and remove obsolete stable-reference assertions.

Changes

Session timeline rendering

Layer / File(s) Summary
Replace structural-sharing state
web/src/components/assistant-ui/session-row-equality.ts, web/src/components/assistant-ui/session-timeline.logic.ts
The timeline removes stable-row state and public exports. sessionRowEqual remains available for semantic row comparison.
Cover resolved clarification rendering
web/src/components/assistant-ui/__tests__/session-thread.test.tsx
Tests verify cloned clarification payloads render the resolved receipt, selected answer, follow-up assistant text, and no error boundary.
Remove structural-sharing assertions
web/src/components/assistant-ui/__tests__/session-timeline.logic.test.ts
Tests for stable row references and related imports are removed. Core timeline behavior tests remain.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: preventing render loops caused by resolved clarifications.
Linked Issues check ✅ Passed The changes remove render-time state stabilization and add regression coverage for resolved clarifications, directly addressing issue #360.
Out of Scope Changes check ✅ Passed The reviewed changes are limited to the render-loop fix, related refactoring, and regression-test updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-360

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown

Greptile Summary

The PR removes obsolete stateful timeline-row stabilization while retaining semantic equality for memoized row rendering. It also adds integration coverage for resolved clarifications with unstable payload identity and updates internal architecture and QA documentation.

  • Renames the timeline stability helper to focus exclusively on semantic row equality.
  • Removes structural-sharing exports and implementation-detail tests.
  • Adds a full-thread regression covering the clarification receipt, answer, and subsequent transcript content.
  • Updates design and QA references from structural sharing to semantic equality and mounted-DOM stability.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete functional, security, or build regressions identified.

The removed stabilization symbols have no remaining repository consumers, semantic row equality remains wired to the memoized renderer, and the new regression covers the unstable resolved-clarification payload path.

Important Files Changed

Filename Overview
web/src/components/assistant-ui/session-row-equality.ts Cleanly removes stateful structural sharing while preserving the existing per-row memo comparator.
web/src/components/assistant-ui/session-timeline.logic.ts Updates the public timeline exports and documentation consistently, with no remaining repository importers of deleted symbols.
web/src/components/assistant-ui/tests/session-thread.test.tsx Adds integration coverage that exercises volatile clarification payload identity through the production transcript rendering path.
web/src/components/assistant-ui/tests/session-timeline.logic.test.ts Removes tests tied exclusively to the deleted structural-sharing state container while retaining derivation behavior coverage.

Reviews (1): Last reviewed commit: "fix: prevent session timeline render loo..." | Re-trigger Greptile

This branch was successfully deployed

1 active deployment
Preview — 9a886756 Deployed Aug 12, 2026 by vercel[bot]
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.

[Bug][v0.3.0-beta.13] Session thread crashes with React #301

1 participant