fix(kernel,router): rehydrate by CAS content hash (F-021) + narration budget
rehydrate() now scans ArtifactContentStoredEvent (the durable slot->CAS-hash bridge) and fetches stored bytes by content hash, keying the cache by the logical slot name. The slot name is never passed to the hash-keyed CAS, so the odd-length-hex crash is gone and artifact content is restored on cold-start resume. RehydrateTest reworked to use a content-addressed fake store (slot name != content hash) so it actually exercises the bug. Replay (#8) is unaffected — rehydrate is live-resume-only. Also bump router narration maxTokens 1024 -> 4096: reasoning models were spending the whole budget thinking and emitting empty content (finishReason= length), so narrations never reached the TUI. Removes the stale TUI-refactor progress doc.
This commit is contained in:
+8
-5
@@ -10,6 +10,7 @@ import com.correx.core.artifacts.ArtifactState
|
||||
import com.correx.core.artifactstore.ArtifactStore
|
||||
import com.correx.core.events.events.ApprovalDecisionResolvedEvent
|
||||
import com.correx.core.events.events.ApprovalRequestedEvent
|
||||
import com.correx.core.events.events.ArtifactContentStoredEvent
|
||||
import com.correx.core.events.events.ArtifactValidatedEvent
|
||||
import com.correx.core.events.events.OrchestrationResumedEvent
|
||||
import com.correx.core.events.events.RefinementIterationEvent
|
||||
@@ -164,15 +165,17 @@ class DefaultSessionOrchestrator(
|
||||
|
||||
/**
|
||||
* Rebuilds [artifactContentCache] from durable events after a server restart.
|
||||
* Scans all events for [ArtifactValidatedEvent] and re-fetches the stored bytes
|
||||
* from [artifactStore] for each one. Must be called before [resume] to ensure
|
||||
* transition conditions that read artifact content work correctly.
|
||||
* Scans all events for [ArtifactContentStoredEvent], which records the
|
||||
* slot-name -> CAS content-hash mapping at write time, and re-fetches the
|
||||
* stored bytes from [artifactStore] by **content hash** (not slot name).
|
||||
* Must be called before [resume] so transition conditions and `needs`-injection
|
||||
* that read artifact content work correctly after a cold start.
|
||||
*/
|
||||
suspend fun rehydrate(sessionId: SessionId) {
|
||||
repositories.eventStore.readFrom(sessionId, fromSequence = 0L).forEach { event ->
|
||||
val p = event.payload as? ArtifactValidatedEvent ?: return@forEach
|
||||
val p = event.payload as? ArtifactContentStoredEvent ?: return@forEach
|
||||
val key = "${sessionId.value}:${p.artifactId.value}"
|
||||
artifactStore.get(p.artifactId)
|
||||
artifactStore.get(p.contentHash)
|
||||
?.toString(Charsets.UTF_8)
|
||||
?.let { artifactContentCache[key] = it }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user