feat(context): reasoning-thread continuity, L3 doc filtering, and gate hardening
Threads reasoning_content across inference calls and journal renders, filters markdown noise out of L3 repo-knowledge retrieval, adds PlanLinter H3 checks, and tightens filesystem tool output/dir-listing behavior surfaced by prior live QA (see project_readloop_campaign memory).
This commit is contained in:
@@ -7,7 +7,7 @@ import com.correx.core.journal.model.DecisionRecord
|
||||
class DecisionJournalRenderer(private val keepLast: Int = 40) {
|
||||
fun render(state: DecisionJournalState, summaryText: String? = null): String {
|
||||
if (state.records.isEmpty() && summaryText == null) return ""
|
||||
val visible = foldResolvedRetries(state.records)
|
||||
val visible = foldResolvedRetries(state.records).filter { it.kind in AGENT_RELEVANT_KINDS }
|
||||
return buildString {
|
||||
appendLine("## Decision history (chronological — ground truth)")
|
||||
if (summaryText != null) {
|
||||
@@ -16,7 +16,7 @@ class DecisionJournalRenderer(private val keepLast: Int = 40) {
|
||||
appendLine("+${state.lowSalienceOmittedCount} routine transitions/retries omitted")
|
||||
}
|
||||
}
|
||||
visible.takeLast(keepLast).forEach { appendLine("- [${it.kind}] ${it.summary}") }
|
||||
visible.takeLast(keepLast).forEach { appendLine("- ${it.summary}") }
|
||||
}.trimEnd()
|
||||
}
|
||||
|
||||
@@ -46,4 +46,15 @@ class DecisionJournalRenderer(private val keepLast: Int = 40) {
|
||||
record.copy(summary = "$stage: $count retr${if (count == 1) "y" else "ies"}, resolved — stage completed")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* What actually shapes an agent's next decision: the goal, human steering, and failures
|
||||
* worth not repeating. APPROVAL/ARTIFACT/TRANSITION are bookkeeping for the audit trail —
|
||||
* agents don't act on "Approval APPROVED (tier T2)" or "Advanced x → y", so they're
|
||||
* dropped from the render (still present in [DecisionJournalState.records] for the journal).
|
||||
*/
|
||||
private val AGENT_RELEVANT_KINDS =
|
||||
setOf(DecisionKind.INTENT, DecisionKind.STEERING, DecisionKind.PREEMPT, DecisionKind.FAILURE, DecisionKind.RETRY)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-8
@@ -27,11 +27,28 @@ class DecisionJournalRendererTest {
|
||||
records = listOf(record(1), record(2)),
|
||||
)
|
||||
val result = renderer.render(state)
|
||||
assertTrue(result.contains("- [INTENT] summary-1"))
|
||||
assertTrue(result.contains("- [INTENT] summary-2"))
|
||||
assertTrue(result.contains("- summary-1"))
|
||||
assertTrue(result.contains("- summary-2"))
|
||||
assertFalse(result.contains("omitted"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `approval, artifact and transition records are excluded from the render`() {
|
||||
val state = DecisionJournalState(
|
||||
records = listOf(
|
||||
record(1, DecisionKind.APPROVAL, "Approval APPROVED (tier T2)"),
|
||||
record(2, DecisionKind.ARTIFACT, "Validated artifact x at stage y"),
|
||||
record(3, DecisionKind.TRANSITION, "Advanced a → b (t1)").copy(stageId = "b", fromStageId = "a"),
|
||||
record(4, DecisionKind.FAILURE, "Stage b failed: boom"),
|
||||
),
|
||||
)
|
||||
val result = renderer.render(state)
|
||||
assertFalse(result.contains("Approval APPROVED"))
|
||||
assertFalse(result.contains("Validated artifact"))
|
||||
assertFalse(result.contains("Advanced a"))
|
||||
assertTrue(result.contains("- Stage b failed: boom"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `summaryText appears before records`() {
|
||||
val state = DecisionJournalState(
|
||||
@@ -42,7 +59,7 @@ class DecisionJournalRendererTest {
|
||||
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]") }
|
||||
val recordIdx = lines.indexOfFirst { it.startsWith("- summary") }
|
||||
assertTrue(headerIdx >= 0)
|
||||
assertTrue(summaryIdx > headerIdx)
|
||||
assertTrue(recordIdx > summaryIdx)
|
||||
@@ -75,7 +92,7 @@ class DecisionJournalRendererTest {
|
||||
assertTrue(result.contains("## Decision history"))
|
||||
assertTrue(result.contains("Compacted summary"))
|
||||
assertTrue(result.contains("+2 routine transitions/retries omitted"))
|
||||
assertFalse(result.contains("- ["))
|
||||
assertFalse(result.contains("- "))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,8 +107,8 @@ class DecisionJournalRendererTest {
|
||||
)
|
||||
val result = renderer.render(state)
|
||||
assertFalse(result.contains("did not produce"), "resolved retry detail must not render")
|
||||
assertTrue(result.contains("- [RETRY] scaffold: 2 retries, resolved — stage completed"))
|
||||
assertTrue(result.contains("- [TRANSITION] Advanced scaffold → hook"))
|
||||
assertTrue(result.contains("- scaffold: 2 retries, resolved — stage completed"))
|
||||
assertFalse(result.contains("Advanced scaffold"), "TRANSITION records are audit-only, not agent-relevant")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -102,7 +119,7 @@ class DecisionJournalRendererTest {
|
||||
),
|
||||
)
|
||||
val result = renderer.render(state)
|
||||
assertTrue(result.contains("- [RETRY] Retry 1/3 of hook: did not produce"))
|
||||
assertTrue(result.contains("- Retry 1/3 of hook: did not produce"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,6 +132,6 @@ class DecisionJournalRendererTest {
|
||||
),
|
||||
)
|
||||
val result = renderer.render(state)
|
||||
assertTrue(result.contains("- [RETRY] Retry 1/3 of scaffold: regression"))
|
||||
assertTrue(result.contains("- Retry 1/3 of scaffold: regression"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user