fix(kernel,tools,validation): unblock role_pipeline end-to-end + QA audit

Live QA audit of role_pipeline against a sample repo surfaced and fixed a
chain of defects that prevented any tool+artifact workflow from running
end-to-end. The pipeline now completes cleanly with a real, validated,
reviewed file change.

- F-008 workflow: propagate stage token_budget -> generationConfig.maxTokens
  (TomlWorkflowLoader) so large stages stop truncating at the 2048 default.
- F-009 tools/kernel: file_read missing-file is recoverable; recoverable tool
  errors feed back into the loop instead of aborting the stage.
- F-010/F-018 kernel: reject premature stage_complete and nudge the model to
  emit the owed artifact / invoke a write tool (bounded by MAX_TOOL_ROUNDS).
- F-011 schemas: list-typed artifact fields string -> array (analysis/design/
  impl_plan) to match model output.
- F-012 kernel: strip an outer markdown code fence from LLM artifacts.
- F-013 validation: payload-validation failures are retryable; structural
  failures stay terminal (wires the invariant-#7 reject+retry contract).
- F-014 tools: file_edit schema matches its real params; edits emit a diff.
- F-015 kernel: record tool-execution events + materialise a real file_written
  artifact from the on-disk write; gate validation so a no-write stage cannot
  be rubber-stamped (no more false-success runs).
- F-016 server: raise stageTimeoutMs 60s -> 180s for slow local models.
- F-019 artifacts/kernel: file_written artifact carries the unified diff so the
  reviewer can verify the change (shared DiffUtil; file_write emits a diff too).
- F-020 tools: model-correctable file_edit failures are recoverable + steer
  toward replace/file_write over the fragile patch op.

Full findings register (F-001..F-021, incl. open F-021 resume rehydrate bug)
in qa/audit-report-2026-06-08.md. All module tests green.
This commit is contained in:
2026-06-08 21:51:21 +04:00
parent d518400b5f
commit b407b47503
16 changed files with 664 additions and 45 deletions
@@ -6,6 +6,7 @@ import com.correx.core.artifacts.kind.TypedArtifactSlot
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.StageId
import com.correx.core.events.types.TransitionId
import com.correx.core.inference.GenerationConfig
import com.correx.core.transitions.graph.StageConfig
import com.correx.core.transitions.graph.TransitionEdge
import com.correx.core.transitions.graph.WorkflowGraph
@@ -91,6 +92,14 @@ class TomlWorkflowLoader(
needs = s.needs.map { ArtifactId(it) }.toSet(),
allowedTools = s.allowedTools.toSet(),
tokenBudget = s.tokenBudget,
// Propagate the declared token budget to the inference completion cap.
// Without this the StageConfig default (maxTokens=2048) is used, truncating
// larger artifacts (finishReason=length) → invalid JSON → validation failure.
generationConfig = GenerationConfig(
temperature = 0.7,
topP = 1.0,
maxTokens = s.tokenBudget,
),
maxRetries = s.maxRetries,
metadata = buildMap {
s.prompt?.let { put("prompt", resolvePromptPath(it, workflowDir)) }