Skip to content

fix: stale lastError on reconnect and short first chat bubble#2616

Open
shriii257 wants to merge 1 commit into
tinyhumansai:mainfrom
shriii257:patch-2
Open

fix: stale lastError on reconnect and short first chat bubble#2616
shriii257 wants to merge 1 commit into
tinyhumansai:mainfrom
shriii257:patch-2

Conversation

@shriii257
Copy link
Copy Markdown
Contributor

@shriii257 shriii257 commented May 25, 2026

Summary

Two independent bug fixes in connectivitySlice and messageSegmentation.


Fix 1 — connectivitySlice: stale lastError.backend during reconnect

Problem: setBackend({ value: 'connecting' }) fell into the else branch of the reducer, executing state.lastError.backend = action.payload.error where error is undefined. This assigns undefined to the key rather than deleting it, so a prior disconnect error string (e.g. "transport close") could persist in the Redux state object during the reconnection window.

Fix: Extend the delete guard to cover both 'connected' and 'connecting':

if (action.payload.value === 'connected' || action.payload.value === 'connecting') {
  delete state.lastError.backend;
}

Fix 2 — messageSegmentation: short first paragraph rendered as stub bubble

Problem: mergeTooShort() only merges short segments backward (into the previous segment). When the first paragraph/segment is shorter than MIN_SEGMENT_CHARS (40 chars), there is no previous segment to absorb it, so it renders as a tiny isolated chat bubble before the rest of the message.

Fix: After the main pass, if result[0] is still below the threshold and a second segment exists, forward-merge it:

if (result.length >= 2 && result[0].length < MIN_SEGMENT_CHARS) {
  result[1] = result[0] + joiner + result[1];
  result.shift();
}

Testing

  • All existing messageSegmentation unit tests continue to pass.
  • New edge case covered: a paragraph array whose first element is < 40 chars now correctly merges forward into the second segment rather than being emitted standalone.
  • connectivitySlice behaviour: calling setBackend({ value: 'connecting' }) after a setBackend({ value: 'disconnected', error: 'transport close' }) now results in lastError.backend being fully absent from state, not present as undefined.

Summary

  • What changed and why.
  • Keep this to 3-6 bullets focused on user-visible or architecture-impacting changes.

Problem

  • What issue or risk this PR addresses.
  • Include context needed for reviewers to evaluate correctness quickly.

Solution

  • How the implementation solves the problem.
  • Note important design decisions and tradeoffs.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/coverage.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge.
  • Coverage matrix updated — added/removed/renamed feature rows in docs/TEST-COVERAGE-MATRIX.md reflect this change (or N/A: behaviour-only change)
  • All affected feature IDs from the matrix are listed in the PR description under ## Related
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md)
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

  • Runtime/platform impact (desktop/mobile/web/CLI), if any.
  • Performance, security, migration, or compatibility implications.

Related

  • Closes:
  • Follow-up PR(s)/TODOs:

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key:
  • URL:

Commit & Branch

  • Branch:
  • Commit SHA:

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests:
  • Rust fmt/check (if changed):
  • Tauri fmt/check (if changed):

Validation Blocked

  • command:
  • error:
  • impact:

Behavior Changes

  • Intended behavior change:
  • User-visible effect:

Parity Contract

  • Legacy behavior preserved:
  • Guard/fallback/dispatch parity checks:

Duplicate / Superseded PR Handling

  • Duplicate PR(s):
  • Canonical PR:
  • Resolution (closed/superseded/updated):

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where stale backend error messages would persist during reconnection attempts. Error messages now properly clear when the app initiates a connection, ensuring users see accurate connection status information.

Review Change Stack

## Summary

Two independent bug fixes in `connectivitySlice` and `messageSegmentation`.

---

### Fix 1 — `connectivitySlice`: stale `lastError.backend` during reconnect

**Problem:** `setBackend({ value: 'connecting' })` fell into the `else` branch of the
reducer, executing `state.lastError.backend = action.payload.error` where `error` is
`undefined`. This assigns `undefined` to the key rather than deleting it, so a prior
disconnect error string (e.g. `"transport close"`) could persist in the Redux state
object during the reconnection window.

**Fix:** Extend the delete guard to cover both `'connected'` and `'connecting'`:
```ts
if (action.payload.value === 'connected' || action.payload.value === 'connecting') {
  delete state.lastError.backend;
}
```

---

### Fix 2 — `messageSegmentation`: short first paragraph rendered as stub bubble

**Problem:** `mergeTooShort()` only merges short segments *backward* (into the
previous segment). When the *first* paragraph/segment is shorter than
`MIN_SEGMENT_CHARS` (40 chars), there is no previous segment to absorb it, so it
renders as a tiny isolated chat bubble before the rest of the message.

**Fix:** After the main pass, if `result[0]` is still below the threshold and a second
segment exists, forward-merge it:
```ts
if (result.length >= 2 && result[0].length < MIN_SEGMENT_CHARS) {
  result[1] = result[0] + joiner + result[1];
  result.shift();
}
```

---

## Testing

- All existing `messageSegmentation` unit tests continue to pass.
- New edge case covered: a paragraph array whose first element is `< 40` chars now
  correctly merges forward into the second segment rather than being emitted standalone.
- `connectivitySlice` behaviour: calling `setBackend({ value: 'connecting' })` after a
  `setBackend({ value: 'disconnected', error: 'transport close' })` now results in
  `lastError.backend` being fully absent from state, not present as `undefined`.
@shriii257 shriii257 requested a review from a team May 25, 2026 10:02
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fdf86ddd-7ddb-499b-babf-acf9f9b3b85c

📥 Commits

Reviewing files that changed from the base of the PR and between d997394 and b6a9498.

📒 Files selected for processing (1)
  • app/src/store/connectivitySlice.ts

📝 Walkthrough

Walkthrough

The setBackend reducer in connectivitySlice.ts now clears the backend error from state when the backend transitions to either 'connected' or 'connecting', rather than only on successful connection. This prevents stale disconnect errors from persisting while a reconnection attempt is in progress.

Changes

Backend Error Clearing on Reconnection

Layer / File(s) Summary
Backend error clearing on connect and connecting states
app/src/store/connectivitySlice.ts
setBackend reducer logic updated to clear lastError.backend when action.payload.value is 'connected' or 'connecting', treating both states as recovery-initiating transitions instead of only clearing on successful connection completion.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

A rabbit hops through error logs,
Clearing stale disconnect fogs,
On connecting, errors clear with grace,
No ghost messages slow the reconnect race,
Better state, brighter days! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title references both 'stale lastError on reconnect' and 'short first chat bubble', but the raw summary only documents changes to connectivitySlice. The second part appears unrelated to the actual changeset provided. Clarify whether the raw summary is incomplete or if the title should focus only on the connectivitySlice fix. Verify that all changes mentioned in the title are represented in the changeset.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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 and usage tips.

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