kernel: deterministic static_check stage (§B-§5) + critique-outcome producer (§B-§6)
Two reviewer-reliability tracks, both deterministic and unit-verified (no model/network). §B-§5 — static_check stage seam. The StaticAnalysisRunner + StaticFindingsRecordedEvent + reviewer-context filter already existed; what was missing was a stage that runs the tool and emits the event. Added: - StaticCheckStageExecutor: reads stage metadata (static_tool/static_argv), runs the configured command via StaticAnalysisRunner, returns a StaticFindingsRecordedEvent. No-op (empty findings) when no runner is wired or no command is configured — safe to carry unconfigured. - A deterministic-stage seam in DefaultSessionOrchestrator.enterStage: any stage with metadata["stage_type"] == "static_check" is run by the executor instead of the LLM subagent, then advances on its (unconditional) exit edge. - TomlWorkflowLoader: stage_type/static_tool/static_argv fields → StageConfig.metadata. - role_pipeline.toml: a static_check stage between implementer and reviewer (no-op until static_argv + a CommandRunner are set; activation is live-QA-gated, see StaticAnalysisRunner doc). §B-§6 — critique-outcome producer. The CritiqueFinding type + CriticCalibrationProjection existed but nothing fed them. Added: - CritiqueFindingsRecordedEvent (+ CritiqueVerdict): the producing side — a critic's findings + verdict for one review iteration, carrying modelHash for per-model calibration. - CritiqueOutcomeCorrelator: pure loop-resolution logic deciding UPHELD (fixed between rounds) / DISMISSED (persisted into an approved final) / INCONCLUSIVE (open at a non-approved terminal), per critic (role + modelHash) and per finding id. - A hook in completeWorkflow/failWorkflow that correlates recorded findings into CritiqueOutcomeCorrelatedEvents at loop resolution — no-op when none recorded, idempotent. (LLM-side finding emission stays a separate model-gated activation.) Tests: StaticCheckStageExecutorTest (4), StaticCheckStageTest integration (1, fake runner → event + transition), CritiqueOutcomeCorrelatorTest (8), CritiqueCalibrationWiringTest integration (1, seeded findings → outcomes at completion), updated RolePipelineWorkflowTest. Full suites for core:events/kernel/critique, infrastructure:workflow, testing:integration green; detekt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Role pipeline: analyst → architect → planner → implementer ⇄ reviewer
|
||||
# Role pipeline: analyst → architect → planner → implementer → static_check ⇄ reviewer
|
||||
#
|
||||
# Each stage produces a typed artifact that the next stage `needs`, so work flows forward
|
||||
# without a human relaying notes. The decision journal (pinned into every stage's context)
|
||||
@@ -69,6 +69,19 @@ allowed_tools = ["file_read", "file_write", "file_edit", "ShellTool"]
|
||||
token_budget = 32768
|
||||
max_retries = 3
|
||||
|
||||
# 4b. Deterministic static analysis (NO LLM). Runs a configured tool (compiler/ktlint/detekt)
|
||||
# over the patch and records its findings as a StaticFindingsRecordedEvent, which the
|
||||
# reviewer-context filter then strips from the reviewer's context so the LLM reviewer spends
|
||||
# its attention on semantic review rather than re-finding what the build already reports.
|
||||
# No-op until `static_argv` is set (and a CommandRunner is wired) — safe to carry unconfigured.
|
||||
# Activate e.g. with: static_argv = "./gradlew detekt --console=plain"
|
||||
[[stages]]
|
||||
id = "static_check"
|
||||
stage_type = "static_check"
|
||||
static_tool = "detekt"
|
||||
token_budget = 0
|
||||
max_retries = 0
|
||||
|
||||
# 5. Review the patch against the plan AND the analyst's acceptance criteria. The reviewer
|
||||
# needs `analysis` so it judges the diff against concrete, pre-stated criteria (§5 narrow
|
||||
# question) rather than whole files against taste.
|
||||
@@ -103,13 +116,21 @@ to = "implementer"
|
||||
condition_type = "artifact_validated"
|
||||
condition_artifact_id = "impl_plan"
|
||||
|
||||
# implementer → static_check (once the patch is validated) → reviewer. The static_check stage
|
||||
# produces no artifact, so its exit edge is unconditional (always_true).
|
||||
[[transitions]]
|
||||
id = "implementer-to-reviewer"
|
||||
id = "implementer-to-static_check"
|
||||
from = "implementer"
|
||||
to = "reviewer"
|
||||
to = "static_check"
|
||||
condition_type = "artifact_validated"
|
||||
condition_artifact_id = "patch"
|
||||
|
||||
[[transitions]]
|
||||
id = "static_check-to-reviewer"
|
||||
from = "static_check"
|
||||
to = "reviewer"
|
||||
condition_type = "always_true"
|
||||
|
||||
# --- verdict-gated loop exit / re-entry ---
|
||||
|
||||
[[transitions]]
|
||||
|
||||
Reference in New Issue
Block a user