feat(workflow): sample review_report schema + implementer↔reviewer loop

This commit is contained in:
2026-06-04 00:56:50 +04:00
parent fac6a29178
commit 8d67f5b03e
4 changed files with 173 additions and 0 deletions
+4
View File
@@ -117,3 +117,7 @@ backend = "in_memory" # or "turbovec"
# id = "review_report" # id = "review_report"
# schema_path = "schemas/review_report.json" # schema_path = "schemas/review_report.json"
# llm_emitted = true # llm_emitted = true
#
# The bundled examples/workflows/review_loop.toml uses this kind: the reviewer emits a
# review_report whose `verdict` field gates the implementer↔reviewer loop via
# artifact_field_equals transitions. See docs/schemas/review_report.json for the schema.
+15
View File
@@ -0,0 +1,15 @@
{
"type": "object",
"properties": {
"verdict": {
"type": "string",
"description": "approved | changes_requested"
},
"notes": {
"type": "string",
"description": "reviewer rationale and requested changes"
}
},
"required": ["verdict"],
"additionalProperties": true
}
+58
View File
@@ -0,0 +1,58 @@
# Implementer ↔ reviewer refinement loop.
#
# The reviewer emits a validated `review_report` artifact carrying a `verdict` field.
# The loop exits to `done` when verdict == "approved" and loops back to `implement`
# otherwise (verdict != "approved"). The runtime refinement guard caps the
# review→implement cycle at `implement.max_retries` iterations and then escalates.
#
# Requires a `review_report` artifact kind declared in config:
# [[artifacts]]
# id = "review_report"
# schema_path = "schemas/review_report.json"
# llm_emitted = true
id = "review_loop"
start = "implement"
[[stages]]
id = "implement"
prompt = "prompts/implement.md"
produces = [{ name = "patch", kind = "file_written" }]
allowed_tools = ["file_write"]
token_budget = 8192
max_retries = 3
[[stages]]
id = "review"
prompt = "prompts/review.md"
needs = ["patch"]
produces = [{ name = "review_report", kind = "review_report" }]
token_budget = 8192
max_retries = 3
[[transitions]]
id = "implement-to-review"
from = "implement"
to = "review"
condition_type = "artifact_validated"
condition_artifact_id = "patch"
[[transitions]]
id = "review-approved"
from = "review"
to = "done"
condition_type = "artifact_field_equals"
condition_artifact_id = "review_report"
condition_field = "verdict"
condition_value = "approved"
condition_operator = "eq"
[[transitions]]
id = "review-changes-requested"
from = "review"
to = "implement"
condition_type = "artifact_field_equals"
condition_artifact_id = "review_report"
condition_field = "verdict"
condition_value = "approved"
condition_operator = "neq"
@@ -0,0 +1,96 @@
package com.correx.infrastructure.workflow
import com.correx.core.artifacts.kind.ConfigArtifactKind
import com.correx.core.artifacts.kind.DefaultArtifactKindRegistry
import com.correx.core.artifacts.kind.JsonSchema
import com.correx.core.artifacts.kind.JsonSchemaProperty
import com.correx.core.events.types.StageId
import com.correx.core.transitions.conditions.ArtifactFieldEquals
import com.correx.core.transitions.conditions.FieldOperator
import org.junit.jupiter.api.Test
import java.nio.file.Files
import kotlin.io.path.writeText
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ReviewLoopWorkflowTest {
private val registry = DefaultArtifactKindRegistry().apply {
register(
ConfigArtifactKind(
id = "review_report",
schema = JsonSchema(
type = "object",
properties = mapOf("verdict" to JsonSchemaProperty(type = "string")),
required = listOf("verdict"),
additionalProperties = true,
),
llmEmitted = true,
),
)
}
private val loader = TomlWorkflowLoader(registry)
private val toml = """
id = "review_loop"
start = "implement"
[[stages]]
id = "implement"
prompt = "prompts/implement.md"
produces = [{ name = "patch", kind = "file_written" }]
allowed_tools = ["file_write"]
max_retries = 3
[[stages]]
id = "review"
prompt = "prompts/review.md"
needs = ["patch"]
produces = [{ name = "review_report", kind = "review_report" }]
max_retries = 3
[[transitions]]
id = "implement-to-review"
from = "implement"
to = "review"
condition_type = "artifact_validated"
condition_artifact_id = "patch"
[[transitions]]
id = "review-approved"
from = "review"
to = "done"
condition_type = "artifact_field_equals"
condition_artifact_id = "review_report"
condition_field = "verdict"
condition_value = "approved"
condition_operator = "eq"
[[transitions]]
id = "review-changes-requested"
from = "review"
to = "implement"
condition_type = "artifact_field_equals"
condition_artifact_id = "review_report"
condition_field = "verdict"
condition_value = "approved"
condition_operator = "neq"
""".trimIndent()
@Test
fun `review loop parses with verdict-gated edges`() {
val path = Files.createTempFile("review_loop", ".toml").also { it.writeText(toml) }
val graph = loader.load(path)
val review = graph.stages[StageId("review")]!!
assertTrue(review.produces.any { it.name.value == "review_report" && it.kind.llmEmitted })
val approved = graph.transitions.first { it.to == StageId("done") }.condition as ArtifactFieldEquals
assertEquals("verdict", approved.field)
assertEquals("approved", approved.value)
assertEquals(FieldOperator.EQ, approved.operator)
val changes = graph.transitions.first { it.to == StageId("implement") }.condition as ArtifactFieldEquals
assertEquals(FieldOperator.NEQ, changes.operator)
}
}