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:
+29
@@ -1,9 +1,38 @@
|
||||
package com.correx.core.events.events
|
||||
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/** A critic's verdict for one review iteration. */
|
||||
@Serializable
|
||||
enum class CritiqueVerdict { APPROVED, CHANGES_REQUESTED }
|
||||
|
||||
/**
|
||||
* The findings a critic (plan critic or code reviewer) raised in one review iteration, plus its
|
||||
* [verdict] for that iteration. This is the **producing side** of critique calibration: the
|
||||
* reviewer-loop runtime correlates the sequence of these across iterations into
|
||||
* [CritiqueOutcomeCorrelatedEvent]s (see CritiqueOutcomeCorrelator), which the
|
||||
* `:core:critique` projection then folds into per-(model, role) precision.
|
||||
*
|
||||
* [iteration] is the refinement-loop iteration (1-based) this review belongs to, so the
|
||||
* correlator can order reviews and tell whether a finding was fixed between rounds. [modelHash]
|
||||
* identifies the model that produced the findings (carried through to the outcome event so
|
||||
* calibration is per-model).
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("CritiqueFindingsRecorded")
|
||||
data class CritiqueFindingsRecordedEvent(
|
||||
val sessionId: SessionId,
|
||||
val stageId: StageId,
|
||||
val role: CritiqueRole,
|
||||
val modelHash: String,
|
||||
val iteration: Int,
|
||||
val verdict: CritiqueVerdict,
|
||||
val findings: List<CritiqueFinding>,
|
||||
) : EventPayload
|
||||
|
||||
/**
|
||||
* How a prior [CritiqueFinding] actually turned out once the surrounding loop resolved.
|
||||
* UPHELD = the finding was confirmed/actioned; DISMISSED = rejected as a false positive;
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.correx.core.events.events.ChatSessionStartedEvent
|
||||
import com.correx.core.events.events.ClarificationAnsweredEvent
|
||||
import com.correx.core.events.events.ClarificationRequestedEvent
|
||||
import com.correx.core.events.events.ChatTurnEvent
|
||||
import com.correx.core.events.events.CritiqueFindingsRecordedEvent
|
||||
import com.correx.core.events.events.CritiqueOutcomeCorrelatedEvent
|
||||
import com.correx.core.events.events.RouterNarrationEvent
|
||||
import com.correx.core.events.events.OperatorProfileBoundEvent
|
||||
@@ -142,6 +143,7 @@ val eventModule = SerializersModule {
|
||||
subclass(IdeaDiscardedEvent::class)
|
||||
subclass(IdeaPromotedEvent::class)
|
||||
subclass(CritiqueOutcomeCorrelatedEvent::class)
|
||||
subclass(CritiqueFindingsRecordedEvent::class)
|
||||
subclass(StageCheckpointPassedEvent::class)
|
||||
subclass(StageCheckpointFailedEvent::class)
|
||||
subclass(PossibleContradictionFlaggedEvent::class)
|
||||
|
||||
Reference in New Issue
Block a user