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:
@@ -9,6 +9,7 @@ import com.correx.core.inference.InferenceRecord
|
||||
import com.correx.core.inference.InferenceState
|
||||
import com.correx.core.inference.InferenceStatus
|
||||
import com.correx.core.inference.TokenUsage
|
||||
import com.correx.core.utils.TypeId
|
||||
import com.correx.testing.fixtures.EventFixtures.stored
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
@@ -38,6 +39,7 @@ class InferenceProjectorTest {
|
||||
sessionId = SessionId("sess1"),
|
||||
stageId = StageId("stageA"),
|
||||
providerId = ProviderId("providerX"),
|
||||
promptArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
val newState = projector.apply(initialState, event)
|
||||
@@ -67,6 +69,7 @@ class InferenceProjectorTest {
|
||||
providerId = ProviderId("providerX"),
|
||||
tokensUsed = TokenUsage(50, 50),
|
||||
latencyMs = 500L,
|
||||
responseArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
val newState = projector.apply(initialState, event)
|
||||
@@ -88,6 +91,7 @@ class InferenceProjectorTest {
|
||||
sessionId = SessionId("sess1"),
|
||||
stageId = StageId("stageA"),
|
||||
providerId = ProviderId("providerX"),
|
||||
promptArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
var currentState = projector.apply(initialState, startEvent)
|
||||
@@ -102,6 +106,7 @@ class InferenceProjectorTest {
|
||||
providerId = ProviderId("providerX"),
|
||||
tokensUsed = TokenUsage(100, 100),
|
||||
latencyMs = 1000L,
|
||||
responseArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
currentState = projector.apply(currentState, completeEvent)
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.correx.core.inference.InferenceReducer
|
||||
import com.correx.core.inference.InferenceState
|
||||
import com.correx.core.inference.InferenceStatus
|
||||
import com.correx.core.inference.TokenUsage
|
||||
import com.correx.core.utils.TypeId
|
||||
import com.correx.testing.fixtures.EventFixtures.stored
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
@@ -36,6 +37,7 @@ class InferenceReducerTest {
|
||||
sessionId = SessionId("sess1"),
|
||||
stageId = StageId("stageA"),
|
||||
providerId = ProviderId("providerX"),
|
||||
promptArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
val newState = reducer.reduce(initialState, event)
|
||||
@@ -65,6 +67,7 @@ class InferenceReducerTest {
|
||||
providerId = ProviderId("providerX"),
|
||||
tokensUsed = TokenUsage(50, 50),
|
||||
latencyMs = 500L,
|
||||
responseArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
val newState = reducer.reduce(initialState, event)
|
||||
@@ -176,6 +179,7 @@ class InferenceReducerTest {
|
||||
providerId = ProviderId("providerX"),
|
||||
tokensUsed = TokenUsage(50, 50),
|
||||
latencyMs = 500L,
|
||||
responseArtifactId = TypeId("00".repeat(32)),
|
||||
),
|
||||
)
|
||||
val newState = reducer.reduce(initialState, event)
|
||||
|
||||
Reference in New Issue
Block a user