mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 04:33:17 +00:00
796a70999b
Each tenant monitor owns its own `IncidentStore`, but incident and incident-event IDs came from package-level `int64` counters bumped with `++` under nothing but the calling store's mutex. Two tenants recording alerts at once raced on them. `go test -race` failed `TestLeavingMockModeClearsEveryRunningTenantMonitor` on #2698 ([run](https://github.com/rcourtman/Pulse/actions/runs/37652317098/job/112919080928)) at `incidents.go:1753`. The remediation record counter in `remediation.go` had the same shape, and `startPatrolForContext` creates one remediation log per org. **Fix** - All six `internal/ai/memory` ID generators (incident, incident event, remediation record, memory, incident memory, pattern memory) now mint through one atomic helper, `nextSequencedID` in `ids.go`. - The numeric suffix no longer wraps at 1000. Even with atomic counters, a generator that minted more than a thousand IDs in one wall-clock second repeated an ID. That matters because `RecordNote` finds an incident by ID and the incident query deduplicates merged events by ID. The `<prefix><YYYYMMDDhhmmss>-<n>` layout is unchanged. Only `n` can now exceed three digits. - `intToString` lost its last runtime callers and is removed. **Proof** - `internal/ai/memory/ids_test.go` mints 2,400 IDs from every generator on 16 goroutines and records alerts into two tenant stores concurrently. - Against the `origin/main` runtime files (via `-overlay`), `-race` reports DATA RACE at `incidents.go:1753/1760` and `remediation.go:355`, and every generator fails the uniqueness/shape check: four produce duplicate IDs, and `mem`/`pat-mem` produce a wrapped `-0` suffix. - With the fix, `go test -race ./internal/ai/memory/` passes, and `go test -race -count=5 -run TestLeavingMockModeClearsEveryRunningTenantMonitor ./internal/monitoring/` passes. **Residual:** across restarts, only the timestamp separates IDs. If the local clock repeats a second (DST fall-back or a backward step), a restarted sequence could still meet an earlier suffix. Persisted IDs and the stored format are unchanged. The `ai-runtime` contract records this.