State.Save() in internal/state/state.go acquires s.mu.RLock() but then mutates the snapshot:
func(s*State)Save()error{s.mu.RLock()defers.mu.RUnlock()s.snapshot.LastUpdated=time.Now().UTC()// WRITE under RLock!...}
RLock allows concurrent readers, but this is a write operation. If Save() runs concurrently with GetSnapshot() or another Save(), this is a data race.
Impact
Race condition that can cause corrupted LastUpdated timestamps or panic under the race detector. In practice, Save() is called from the watcher goroutine and GetSnapshot() could be called from HTTP handlers concurrently.
Fix
Either:
Change Save() to use s.mu.Lock() (full write lock), or
Compute LastUpdated before acquiring the lock and pass it in, keeping RLock for the marshal+write portion.
## Bug
`State.Save()` in `internal/state/state.go` acquires `s.mu.RLock()` but then mutates the snapshot:
```go
func (s *State) Save() error {
s.mu.RLock()
defer s.mu.RUnlock()
s.snapshot.LastUpdated = time.Now().UTC() // WRITE under RLock!
...
}
```
`RLock` allows concurrent readers, but this is a write operation. If `Save()` runs concurrently with `GetSnapshot()` or another `Save()`, this is a data race.
## Impact
Race condition that can cause corrupted `LastUpdated` timestamps or panic under the race detector. In practice, `Save()` is called from the watcher goroutine and `GetSnapshot()` could be called from HTTP handlers concurrently.
## Fix
Either:
1. Change `Save()` to use `s.mu.Lock()` (full write lock), or
2. Compute `LastUpdated` before acquiring the lock and pass it in, keeping `RLock` for the marshal+write portion.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Bug
State.Save()ininternal/state/state.goacquiress.mu.RLock()but then mutates the snapshot:RLockallows concurrent readers, but this is a write operation. IfSave()runs concurrently withGetSnapshot()or anotherSave(), this is a data race.Impact
Race condition that can cause corrupted
LastUpdatedtimestamps or panic under the race detector. In practice,Save()is called from the watcher goroutine andGetSnapshot()could be called from HTTP handlers concurrently.Fix
Either:
Save()to uses.mu.Lock()(full write lock), orLastUpdatedbefore acquiring the lock and pass it in, keepingRLockfor the marshal+write portion.