feat(validation): plan-compile gate + semantic-review gate (staged verification #19/#20)
Plan-compile gate (#19): PlanCompilationCheck seam (null-on-replay), runPlanCompileGate guards a produced execution_plan slot and compiles its cached content via ExecutionPlanCompiler, emitting PlanCompileCheckedEvent. On failure the architect gets a retryable hand-back and self-corrects; exhaustion terminates the dead-end workflow instead of shipping an uncompilable plan. Semantic-review gate (#20): SemanticReviewer seam + StageConfig.semanticReview opt-in (TOML semantic_review + freestyle plan JSON). runReviewGate reads the FileWritten manifest (never blind context), asks a review-capable model for PR-comment findings, and is advisory — blocks retryably only on FAIL plus a correctness finding >=0.7 confidence, capped at 2 blocks so a stubborn stage completes advisory-only rather than trapping. SemanticReviewerImpl talks to the provider directly; any reviewer error degrades to PASS. REVIEW_MAX_TOKENS is 8192: gemma is a reasoning model and 1024 truncated it mid-reasoning before it reached the JSON verdict (empty content -> parse degraded to PASS). Both gates live-QA'd on the real repo: plan-compile passed on a freestyle web-UI scaffold; semantic review caught all 3 planted bugs in a maxOf() and exercised the block->retry->cap safety valve end-to-end.
This commit is contained in:
+1
@@ -74,6 +74,7 @@ class ExecutionPlanCompiler(
|
||||
// not existence guarantees, so they are excluded here.
|
||||
expectedFiles = s.writes.map { it.trim() }.filter { it.isNotEmpty() && !isGlob(it) },
|
||||
buildExpectation = buildExpectation,
|
||||
semanticReview = s.semanticReview,
|
||||
tokenBudget = DEFAULT_STAGE_TOKEN_BUDGET,
|
||||
metadata = mapOf("promptInline" to s.prompt),
|
||||
)
|
||||
|
||||
+3
@@ -25,6 +25,9 @@ data class PlanStage(
|
||||
// planner emits this under the JSON key `build_expectation`; it resolves at runtime to the
|
||||
// project profile's typecheck/build/test command run as a deterministic Gate 4.
|
||||
@param:JsonProperty("build_expectation") val buildExpectation: String? = null,
|
||||
// Opt-in to the Gate 3 semantic (LLM) reviewer for this stage (staged-verification § Gate 3).
|
||||
// The planner emits this under the JSON key `semantic_review`; absent = off.
|
||||
@param:JsonProperty("semantic_review") val semanticReview: Boolean = false,
|
||||
)
|
||||
|
||||
data class PlanEdge(
|
||||
|
||||
+2
@@ -51,6 +51,7 @@ private data class StageSection(
|
||||
@param:JsonProperty("brief_echo") val briefEcho: Boolean = false,
|
||||
@param:JsonProperty("require_task_decompose") val requireTaskDecompose: Boolean = false,
|
||||
@param:JsonProperty("claim_task") val claimTask: Boolean = false,
|
||||
@param:JsonProperty("semantic_review") val semanticReview: Boolean = false,
|
||||
)
|
||||
|
||||
// condition fields flattened into the transition row
|
||||
@@ -110,6 +111,7 @@ class TomlWorkflowLoader(
|
||||
allowedTools = s.allowedTools.toSet(),
|
||||
writeManifest = s.writes,
|
||||
staticAnalysis = s.staticAnalysis,
|
||||
semanticReview = s.semanticReview,
|
||||
tokenBudget = s.tokenBudget,
|
||||
// Propagate the declared token budget to the inference completion cap.
|
||||
// Without this the StageConfig default (maxTokens=2048) is used, truncating
|
||||
|
||||
Reference in New Issue
Block a user