feat(journal): compaction-aware DecisionJournalRenderer
This commit is contained in:
@@ -3,12 +3,17 @@ package com.correx.core.journal
|
||||
import com.correx.core.journal.model.DecisionJournalState
|
||||
|
||||
class DecisionJournalRenderer(private val keepLast: Int = 40) {
|
||||
fun render(state: DecisionJournalState): String {
|
||||
if (state.records.isEmpty()) return ""
|
||||
val shown = state.records.takeLast(keepLast)
|
||||
fun render(state: DecisionJournalState, summaryText: String? = null): String {
|
||||
if (state.records.isEmpty() && summaryText == null) return ""
|
||||
return buildString {
|
||||
appendLine("## Decision history (chronological — ground truth)")
|
||||
shown.forEach { appendLine("- [${it.kind}] ${it.summary}") }
|
||||
if (summaryText != null) {
|
||||
appendLine(summaryText)
|
||||
if (state.lowSalienceOmittedCount > 0) {
|
||||
appendLine("+${state.lowSalienceOmittedCount} routine transitions/retries omitted")
|
||||
}
|
||||
}
|
||||
state.records.takeLast(keepLast).forEach { appendLine("- [${it.kind}] ${it.summary}") }
|
||||
}.trimEnd()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.correx.core.journal
|
||||
|
||||
import com.correx.core.journal.model.DecisionJournalState
|
||||
import com.correx.core.journal.model.DecisionKind
|
||||
import com.correx.core.journal.model.DecisionRecord
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class DecisionJournalRendererTest {
|
||||
|
||||
private val renderer = DecisionJournalRenderer()
|
||||
|
||||
private fun record(seq: Long, kind: DecisionKind = DecisionKind.INTENT, summary: String = "summary-$seq") =
|
||||
DecisionRecord(sequence = seq, kind = kind, summary = summary)
|
||||
|
||||
@Test
|
||||
fun `empty state with no summaryText returns empty string`() {
|
||||
val state = DecisionJournalState()
|
||||
assertEquals("", renderer.render(state))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `uncompacted state renders records without omitted line`() {
|
||||
val state = DecisionJournalState(
|
||||
records = listOf(record(1), record(2)),
|
||||
)
|
||||
val result = renderer.render(state)
|
||||
assertTrue(result.contains("- [INTENT] summary-1"))
|
||||
assertTrue(result.contains("- [INTENT] summary-2"))
|
||||
assertFalse(result.contains("omitted"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `summaryText appears before records`() {
|
||||
val state = DecisionJournalState(
|
||||
records = listOf(record(1)),
|
||||
lowSalienceOmittedCount = 3,
|
||||
)
|
||||
val result = renderer.render(state, summaryText = "Compaction summary here")
|
||||
val lines = result.lines()
|
||||
val headerIdx = lines.indexOfFirst { it.startsWith("## Decision history") }
|
||||
val summaryIdx = lines.indexOfFirst { it == "Compaction summary here" }
|
||||
val recordIdx = lines.indexOfFirst { it.startsWith("- [INTENT]") }
|
||||
assertTrue(headerIdx >= 0)
|
||||
assertTrue(summaryIdx > headerIdx)
|
||||
assertTrue(recordIdx > summaryIdx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `count line appears when lowSalienceOmittedCount is positive`() {
|
||||
val state = DecisionJournalState(
|
||||
records = listOf(record(1)),
|
||||
lowSalienceOmittedCount = 5,
|
||||
)
|
||||
val result = renderer.render(state, summaryText = "Some summary")
|
||||
assertTrue(result.contains("+5 routine transitions/retries omitted"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no count line when lowSalienceOmittedCount is zero with summaryText`() {
|
||||
val state = DecisionJournalState(
|
||||
records = listOf(record(1)),
|
||||
lowSalienceOmittedCount = 0,
|
||||
)
|
||||
val result = renderer.render(state, summaryText = "Some summary")
|
||||
assertFalse(result.contains("omitted"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `summaryText with empty records list renders header and summary`() {
|
||||
val state = DecisionJournalState(records = emptyList(), lowSalienceOmittedCount = 2)
|
||||
val result = renderer.render(state, summaryText = "Compacted summary")
|
||||
assertTrue(result.contains("## Decision history"))
|
||||
assertTrue(result.contains("Compacted summary"))
|
||||
assertTrue(result.contains("+2 routine transitions/retries omitted"))
|
||||
assertFalse(result.contains("- ["))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user