Fixed 🔒
Race condition in content-based deduplication
Stop and Notification hooks were running simultaneously, both passing the duplicate check before either could save state. This caused duplicate notifications with nearly identical content.
Solution
- Added shared content lock (
AcquireContentLock/ReleaseContentLock) - Serializes duplicate check and state update across all hook types
- Now only one hook can check and save notification state at a time
- Uses file-based locking with 5s TTL for cross-process synchronization
Technical Details
- New methods in
internal/dedup/dedup.go:AcquireContentLock(sessionID)- acquires shared lockReleaseContentLock(sessionID)- releases shared lock
- Lock file:
/tmp/claude-notification-{sessionID}-content.lock - Graceful fallback: if lock acquisition fails, continues without lock (prefers duplicate risk over missed notification)
Full Changelog: v1.6.1...v1.6.2