EventLog and ArtifactStore expose suspend APIs that dispatch work to Dispatchers.IO, but each instance holds and reuses a single JDBC Connection without a mutex or single-threaded owner. EventLog.append at lib/src/main/kotlin/dev/arcp/store/EventLog.kt:41, EventLog.replay at lib/src/main/kotlin/dev/arcp/store/EventLog.kt:95, ArtifactStore.put at lib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:67, ArtifactStore.fetch at lib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:146, and ArtifactStore.sweepExpired at lib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:189 can run concurrently on the same connection. ArtifactStore also starts a background sweep coroutine at lib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:49, and ArtifactStore.adopt at lib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:240 explicitly allows callers to share an existing connection.
Fix prompt: Make each store serialize all access to its JDBC connection. A Mutex around every statement block is the smallest fix; a dedicated single-threaded dispatcher or actor is also acceptable if it is closed cleanly. Ensure ArtifactStore.close() cancels and waits for the sweep job before closing an owned connection, and document whether adopt(connection) requires the caller to coordinate access with other users of that connection. Add coroutine tests that run concurrent append/replay and put/fetch/sweep operations to prove the connection is not used concurrently or closed while a statement is active.
EventLogandArtifactStoreexpose suspend APIs that dispatch work toDispatchers.IO, but each instance holds and reuses a single JDBCConnectionwithout a mutex or single-threaded owner.EventLog.appendatlib/src/main/kotlin/dev/arcp/store/EventLog.kt:41,EventLog.replayatlib/src/main/kotlin/dev/arcp/store/EventLog.kt:95,ArtifactStore.putatlib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:67,ArtifactStore.fetchatlib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:146, andArtifactStore.sweepExpiredatlib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:189can run concurrently on the same connection.ArtifactStorealso starts a background sweep coroutine atlib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:49, andArtifactStore.adoptatlib/src/main/kotlin/dev/arcp/runtime/ArtifactStore.kt:240explicitly allows callers to share an existing connection.Fix prompt: Make each store serialize all access to its JDBC connection. A
Mutexaround every statement block is the smallest fix; a dedicated single-threaded dispatcher or actor is also acceptable if it is closed cleanly. EnsureArtifactStore.close()cancels and waits for the sweep job before closing an owned connection, and document whetheradopt(connection)requires the caller to coordinate access with other users of that connection. Add coroutine tests that run concurrent append/replay and put/fetch/sweep operations to prove the connection is not used concurrently or closed while a statement is active.