Skip to content

fix(sync,chat,notes): delete resurrection, maxSteps persistence, chat quick-settings, notes DnD - #91

Merged
ddutchie merged 2 commits into
mainfrom
ddutchie/syncissues
Jul 22, 2026
Merged

ddutchie merged 2 commits into
mainfrom
ddutchie/syncissues

Conversation

@ddutchie

@ddutchie ddutchie commented Jul 22, 2026 •

Copy link
Copy Markdown
Owner

What does this PR do?

Fixes a sync bug where deleted notes could resurrect, makes the chat "Max steps" limit persist, adds an in-chat quick-settings popover, moves Subagents to a global preference, persists notes folder expand/collapse state, and fixes two notes drag-and-drop issues.

Type of change

  • Bug fix
  • New feature
  • Refactor / code quality
  • Docs / changelog
  • Tests

Details

Sync

  • Deleting a note on desktop, then syncing again before the peer picked up the deletion, let the peer's stale put resurrect the note. Desktop does a physical DELETE (no tombstone), so drainPending's delete UPDATE matched zero rows and the staleness guard in reconcileOne was bypassed (localHlc null). drainPending now inserts a tombstone shell when the delete matches no rows (FK-toggled like applyRemote). Regression test added.

Chat / AI settings

  • "Max steps" reverted to 30 mid-conversation: the backend settings cache dropped maxSteps (and temperature/contextLimit/aiEnabled), and hydrateFromElectron (run after every write-tool turn) let the field-poor backend config shadow the richer localStorage copy. The cache now persists all AI fields and hydrate merges instead of shadowing.
  • New in-chat quick-settings gear popover: model (custom Radix dropdown with Refresh models + Custom model…), max steps, temperature, subagents, and a "More settings…" deep-link. Long model names show a tooltip only when actually truncated.
  • Subagents is now a global preference (aiConfig.subagentsEnabled) surfaced in Settings + the popover; the per-thread pill is removed and setThreadUseSubagents / ChatThread.useSubagents retired (DB column left dormant, no migration).

Notes

  • Folder-tree expand/collapse state is now persisted per-project in localStorage.
  • The "Move to root" drop zone is pinned to the bottom of the panel while dragging (was inline in the scroll list), and lingering drag state after a cross-project drop is cleared via a document-level dragend/drop listener (the dragged element unmounts mid-drag so its onDragEnd never fired).

Screenshots / recording

Checklist

  • npm run type-check:all passes
  • npm run lint passes
  • npm test passes — 1271/1272 pass; the sole failure is tool-schema-optimization.test.ts, a LIVE, opt-in LLM benchmark that failed by its 1-item non-determinism slack (10 >= 11) and is unrelated to these changes
  • npm run test:e2e — not run yet
  • No hardcoded colours — CSS variables only
  • No text-[Npx] pixel font classes — rem equivalents only
  • New IPC handlers wrapped in handle() and return IpcResult<T> — n/a (no new IPC handlers)
  • New DB migrations appended (not edited) in schema.ts — n/a (no schema changes; dormant use_subagents column left as-is)
  • New SQL goes in electron/db/queries.ts — n/a (no new SQL)
  • New dependencies added to ROLE_MAP / licenses.json — n/a (no new deps)
  • New MCP tools registered — n/a (no new MCP tools)
  • --external:<pkg> flags — n/a (unchanged)

Notes for reviewer

  • The tool-schema-optimization failure is a flaky live-model benchmark, not a regression — happy to re-run.
  • The chat_threads.use_subagents DB column is intentionally left dormant (dropping a SQLite column needs a risky table rebuild for no benefit); the global aiConfig.subagentsEnabled now drives behaviour.
  • Per-thread subagents dead code (setThreadUseSubagents, ChatThread.useSubagents) removed from the renderer.
  • Open question deferred: project ordering in the leftmost sidebar is currently most-recently-updated-first (not alphabetical) — not changed in this PR.

Summary by CodeRabbit

  • New Features

    • Added in-chat quick controls for AI model, maximum steps, temperature, and subagents.
    • Added a global Subagents setting for supported providers.
    • Persisted notes-folder expansion and collapse preferences across sessions.
    • Added a pinned “Move to root” drop zone while dragging notes.
  • Bug Fixes

    • Fixed AI settings being reset after subsequent updates.
    • Improved note deletion synchronization to prevent deleted notes from reappearing.
    • Fixed lingering drag-and-drop UI after cross-project moves.
    • Fixed chat maximum-step setting persistence.

… quick-settings, notes DnD

Sync:
- Fix deleted note resurrecting when a peer's stale put is drained after a
  local hard-delete (no local tombstone). drainPending now inserts a tombstone
  shell when the delete UPDATE matches 0 rows so the staleness guard holds.

Chat / AI settings:
- Persist full AI config in the backend cache (maxSteps/temperature/contextLimit/
  aiEnabled) and merge (not shadow) in hydrateFromElectron, fixing "Max steps
  reverts to 30" mid-conversation.
- Add in-chat quick-settings gear popover (model + Refresh/Custom model, max
  steps, temperature, subagents) editing the global aiConfig; tooltip-on-overflow
  for long model names.
- Make Subagents a global preference (aiConfig.subagentsEnabled); remove the
  per-thread pill and retire setThreadUseSubagents / ChatThread.useSubagents.

Notes:
- Persist folder-tree expand/collapse state per-project in localStorage.
- Pin the "Move to root" drop zone to the bottom of the panel; clear lingering
  drag state via a document-level dragend/drop listener after a cross-project drop.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ddutchie, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f0c72606-9da3-480e-9ff1-bd46ea9a1871

📥 Commits

Reviewing files that changed from the base of the PR and between 8ac81e9 and 2e060c2.

📒 Files selected for processing (1)
  • src/store/index.ts
📝 Walkthrough

Walkthrough

Version 2.5.5 adds global AI settings and in-chat controls, persists notes folder expansion state, revises notes drag/drop behavior, hardens sync tombstone handling, and documents regression fixes.

Changes

AI and Chat Configuration

Layer / File(s) Summary
Global AI persistence and settings
src/lib/constants.ts, src/store/..., electron/lib/config-cache.ts, electron/lib/config-cache.test.ts, src/components/settings/AISettings.tsx
AI behavioral settings, including global Subagents configuration, are merged, persisted, and covered by round-trip tests.
In-chat quick settings and streaming integration
src/components/chat/chat-panel/ChatQuickSettings.tsx, src/components/chat/chat-panel/index.tsx, src/store/slices/chat.ts, src/types/index.ts
Chat gains model, max-steps, temperature, and Subagents controls; streaming reads the global setting instead of a thread-level flag, which is removed from chat state and types.

Notes Folder State and Dragging

Layer / File(s) Summary
Persisted folder expansion state
src/store/slices/ui.ts, src/store/index.ts, src/components/notes/..., src/lib/constants.ts
Folder collapse state is keyed by project and lowercased path, restored from local storage, and used by the notes tree.
Pinned root drop zone and drag cleanup
src/components/notes/notes-view.tsx
The “Move to root” target is pinned above the footer and document-level drag listeners clear stale drag state after drops or drag termination.

Sync Convergence

Layer / File(s) Summary
Tombstone shells and regression coverage
shared/sync/engine.ts, shared/sync/engine.test.ts, changelogs/v2.5.5.md
Hard-deleted rows receive tombstone shells during pending-op processing, foreign-key enforcement is restored afterward, stale-oplog convergence is tested, and the changes are documented.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChatQuickSettings
  participant CairnStore
  participant ChatPanel
  User->>ChatQuickSettings: Open and edit chat settings
  ChatQuickSettings->>CairnStore: Update aiConfig
  ChatPanel->>CairnStore: Read global Subagents setting
  ChatPanel->>ChatPanel: Pass useSubagents to sendStream
Loading

Possibly related PRs

  • ddutchie/cairn#76: Both changes modify sync tombstone handling in SyncEngine.drainPending().
  • ddutchie/cairn#90: Both changes modify Subagents state and chat streaming/UI integration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and matches the main sync, chat settings, and notes drag-and-drop changes in the PR.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ddutchie/syncissues

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/store/index.ts`:
- Around line 327-346: Always persist the fully merged configuration through
window.electron.saveAiSettings after constructing mergedAiConfig, including when
backendAiConfig exists. Update the conditional in the hydration logic around
savedConfig and mergedAiConfig, while retaining the existing availability checks
for Electron and saveAiSettings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0fe55f58-79e4-4fde-9f59-9d3f6560e982

📥 Commits

Reviewing files that changed from the base of the PR and between c14cf40 and 8ac81e9.

📒 Files selected for processing (15)
  • changelogs/v2.5.5.md
  • electron/lib/config-cache.test.ts
  • electron/lib/config-cache.ts
  • shared/sync/engine.test.ts
  • shared/sync/engine.ts
  • src/components/chat/chat-panel/ChatQuickSettings.tsx
  • src/components/chat/chat-panel/index.tsx
  • src/components/notes/notes-view.tsx
  • src/components/notes/notes-view/FolderTreeNode.tsx
  • src/components/settings/AISettings.tsx
  • src/lib/constants.ts
  • src/store/index.ts
  • src/store/slices/chat.ts
  • src/store/slices/ui.ts
  • src/types/index.ts
💤 Files with no reviewable changes (2)
  • src/store/slices/chat.ts
  • src/types/index.ts

Comment thread src/store/index.ts
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