feat(validation): auto build-gate on terminal freestyle stage (Gate 4 floor)
Closes the COMPLETED-lie where a freestyle stage passes by producing a schema-valid artifact regardless of whether its build actually succeeded: a verify stage could run 'npm run build', watch it fail, then self-attest a build_verified artifact and transition to done. Tool failures never failed the stage. The compiler now flags the terminal stage autoBuildGate=true when no stage declares an explicit build_expectation. Code-ness is decided at runtime, not compile time (the declared kind is always the generic file_written; only the written paths reveal code): runExecutionGate folds the FileWritten manifest via sessionProducedBuildTarget() and promotes to a PROJECT build when a build manifest (package_json/gradle_module) or an imports_resolve-bearing path was written, then runs the real command from .correx/project.toml [commands]. A non-clean exit fails the stage retryably; a docs-only plan is left untouched. Live-proven (run 3, session 28812b44): gate fired on the real 'npm --prefix frontend run build', exit 2 on a bad tsconfig, RetryAttempted instead of a false COMPLETED. Modules green: transitions+workflow 67, kernel 60.
This commit is contained in:
@@ -43,5 +43,13 @@ data class StageConfig(
|
||||
// deterministic funnel passes and raises advisory PR-comment findings; a high-confidence
|
||||
// correctness FAIL can block retryably until the review-block budget is spent. Default off.
|
||||
val semanticReview: Boolean = false,
|
||||
// Deterministic build-gate floor (staged-verification §Gate 4). Set by the compiler on the plan's
|
||||
// terminal stage when no stage declares an explicit [buildExpectation]. The LLM planner emits every
|
||||
// file-writing stage as the generic `file_written` kind (never a typed code kind) and rarely sets
|
||||
// build_expectation, so a plan that scaffolds real code would otherwise never hit an execution gate.
|
||||
// When this is set and NONE is declared, runExecutionGate promotes to a PROJECT build ONLY IF the
|
||||
// session actually wrote a code module (decided at run time from the FileWritten manifest + path→kind
|
||||
// inference), so a docs-only plan is left untouched. Explicit build_expectation always wins.
|
||||
val autoBuildGate: Boolean = false,
|
||||
val metadata: Map<String, String> = emptyMap(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user