feat(cas): content-addressed artifact store (steps 1–8)
New core:artifacts-store interface + infrastructure/artifacts-cas implementation: segment files + SQLite index, Blake3 hashing, group-commit fsync via flushBefore, recovery tail-scan, manual compactor, and oldest-first disk-cap evictor. Inference events now carry promptArtifactId / responseArtifactId; orchestrators put bytes before emitting. SqliteEventStore wraps its txn in artifactStore.flushBefore so segment data is fsynced before the event commit, making the crash window non-corrupting (TailScanner re-indexes orphan tail records on reopen). Compactor and evictor are mutually exclusive via maintenanceMutex. Step 9 (cloud sync) deferred to a later epic. See docs/reviews/2026-05-18-cas-steps-1-8-review.md for the final review.
This commit is contained in:
@@ -23,7 +23,7 @@ class SessionReplayTest {
|
||||
private val replayer = DefaultEventReplayer(store, projector)
|
||||
|
||||
@Test
|
||||
fun `rebuild session from event stream`() {
|
||||
fun `rebuild session from event stream`(): Unit = kotlinx.coroutines.runBlocking {
|
||||
val sessionId = SessionId("s1")
|
||||
|
||||
val metadataToPayload = mapOf<EventMetadata, EventPayload>(
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.correx.core.sessions.SessionStatus
|
||||
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
|
||||
import com.correx.infrastructure.persistence.InMemoryEventStore
|
||||
import com.correx.testing.fixtures.EventFixtures.newEvent
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@@ -22,7 +23,7 @@ class TransitionReplayIntegrationTest {
|
||||
private val sessionId = SessionId("session-1")
|
||||
|
||||
@Test
|
||||
fun `workflow replay reconstructs COMPLETED session`() {
|
||||
fun `workflow replay reconstructs COMPLETED session`(): Unit = runBlocking {
|
||||
|
||||
val store = InMemoryEventStore()
|
||||
|
||||
@@ -85,7 +86,7 @@ class TransitionReplayIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `workflow replay reconstructs FAILED session`() {
|
||||
fun `workflow replay reconstructs FAILED session`(): Unit = runBlocking {
|
||||
|
||||
val store = InMemoryEventStore()
|
||||
|
||||
@@ -144,7 +145,7 @@ class TransitionReplayIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `replay is deterministic for identical event stream`() {
|
||||
fun `replay is deterministic for identical event stream`(): Unit = runBlocking {
|
||||
val events = listOf(
|
||||
newEvent(
|
||||
sessionId = sessionId,
|
||||
|
||||
Reference in New Issue
Block a user