fix(mcp): idempotent element creation via content-derived IDs#1
Conversation
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR implements idempotent element creation for Excalidraw by introducing deterministic server-derived IDs based on content hash, updating MCP to stop minting IDs, synchronizing frontend sync baselines after WebSocket broadcasts, and adding a deduplication cleanup script. The changes span server ID derivation, MCP handler rewording and behavior modifications, frontend sync tracking, and comprehensive test coverage. ChangesIdempotent Element Writes Implementation
Sequence DiagramsequenceDiagram
participant Client as Client / MCP
participant Server as Server API
participant DB as Database
participant WS as WebSocket
participant Frontend as Frontend Browser
rect rgba(100, 150, 200, 0.5)
Note over Client,Frontend: Element Creation with Deterministic ID
Client->>Server: POST /api/elements (no id provided)
Server->>Server: deriveContentId(project, type, geometry, text, refs)
Server->>DB: INSERT element with derived id
DB-->>Server: Element inserted
Server-->>Client: Response with element.id
Client->>Client: Log assigned element.id
end
rect rgba(100, 150, 200, 0.5)
Note over WS,Frontend: WebSocket Broadcast & Baseline Sync
Server->>WS: Broadcast element_created {element, sync_version}
WS->>Frontend: element_created message
Frontend->>Frontend: updateScene with element
Frontend->>Frontend: applyWsBaseline(scene, [element], [], sync_version)
Frontend->>Frontend: Update lastSyncedElementsRef, lastSyncedHashRef, lastSyncVersionRef
Frontend->>Frontend: Persist lastSyncVersionRef to localStorage
Note over Frontend: syncToBackend detects zero changes
end
rect rgba(150, 100, 200, 0.5)
Note over DB: One-time Deduplication (Phase 1)
DB->>DB: fingerprint() hash elements by content
DB->>DB: bucketByFingerprint() group by fingerprint
DB->>DB: Keep min(sync_version), soft-delete rest
DB->>DB: Bump survivor sync_version
Server->>WS: Broadcast elements_synced
WS->>Frontend: Trigger reconciliation
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Review rate limit: 0/1 reviews remaining, refill in 47 minutes and 51 seconds.Comment |
Stops the skill self-critique loop from doubling diagrams when it re-issues batch_create_elements without clear_canvas. Two layers: 1. Reword MCP response: drop⚠️ "Canvas sync not confirmed" on the success path of create_element / update_element / batch_create_elements. The warning wording was the dominant retry trigger — conservative LLMs read it as failure and re-invoked the same batch ~39ms later. 2. Server-side deterministic IDs: when no id is supplied, derive sha256(project|type|round(x,y,w,h)|text|startRefId|endRefId)[:12]. Same content + same position → same id → upsert (no new row). start/end refs are part of the hash so bound arrows in a batch don't collapse to one row when they share placeholder coords. Also: - MCP stops minting ids in create_element / batch_create_elements (server derives), keeps duplicate_elements minting (intentional copy semantics). - Frontend updates lastSyncedElementsRef + sync_version after WS broadcasts so syncToBackend doesn't re-upload elements it just received. - scripts/dedupe-elements.cjs cleans up existing duplicates (dry-run by default; --execute to mutate). Soft-deletes dups, keeps lowest sync_version. - Skill self-critique loop guidance updated: clear_canvas before re-render OR use update_element for incremental fixes. Tests: +16 new (idempotency + dedupe script). Full suite 304/304 green.
39f5379 to
3c23202
Compare
Server now derives content-based IDs (sha256 of project|type|coords|text|refs) when caller omits id. Same content → same id → upsert; re-issued batch_create no longer doubles diagrams. Also reworded MCP success-path warnings (was the dominant retry trigger), MCP-side ID generation removed, frontend WS handlers now update sync baseline, added scripts/dedupe-elements.cjs cleanup, skill re-render guidance updated. Tests 304/304 (16 new). Plan: plans/260504-0319-mcp-idempotent-element-writes/
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Chores
Tests