feat(orchestration): plan grounding, positive-pattern mining, stage-prompt audition rig
Vikunja #167/#168/#169. #167 PlanGrounder (infrastructure/workflow): build-prereq + touches-scope existence grounding, emits PlanGroundingEvaluatedEvent. Deterministic fold over recorded workspace/plan events (invariants #8/#9). #168 positive-pattern mining (SessionOrchestratorPlanPatterns): mine SuccessfulPlanShape from cross-session log — a locked plan whose own workflow later completed — and inject the closest-resembling plan shape as L0/SYSTEM advisory context for the planning stage. Keyword-Jaccard resemblance, no LLM/embedder, replays identically. Advisory only (#3). #169 stage-prompt audit + CORREX_STAGE_GUIDANCE ON/OFF toggle in SessionOrchestratorExecution. RunCommand gains --intent to seed a freestyle session over REST. Also: workspace verification events + concept-compiler wiring. ./gradlew check green.
This commit is contained in:
@@ -22,12 +22,21 @@ data class ConceptPromotedEvent(
|
||||
// A dedicated system session (ConceptCompilerService.SYSTEM_SESSION) — concepts are cross-session,
|
||||
// so they live on their own stream rather than polluting any user session's replay.
|
||||
val sessionId: SessionId,
|
||||
// Gate-agnostic fingerprint of the recurring failure (see FailureFingerprint).
|
||||
// Gate-agnostic fingerprint of the recurring failure (see FailureFingerprint) — the last-seen
|
||||
// instance, used as the L3 instance-recall id.
|
||||
val fingerprint: String,
|
||||
// Reusable class key `gate + normalized(signature)` the concept is promoted on (design §"class key").
|
||||
// Defaulted for back-compat with v1 events that predate class-key promotion.
|
||||
val classKey: String = "",
|
||||
// The gate the failure recurred on ("contract" | "review" | "plan-compile" | "lint" | "static" | …).
|
||||
val gate: String,
|
||||
// Templated, retrieval-friendly concept text injected into L3.
|
||||
val conceptText: String,
|
||||
// Count of validated fixes observed at promotion time (≥ threshold).
|
||||
val occurrences: Int,
|
||||
// Reference to the validated fix: the CAS path + post-image hash of the file the resolving stage
|
||||
// wrote to clear this failure (design 2026-07-12-acr-concept-compiler.md §"carry the fix").
|
||||
// Null when no file write was observed between the retry and the completion. Additive/back-compat.
|
||||
val fixPath: String? = null,
|
||||
val fixHash: String? = null,
|
||||
) : EventPayload
|
||||
|
||||
@@ -74,6 +74,34 @@ data class CapabilityGapDetectedEvent(
|
||||
val timestampMs: Long,
|
||||
) : EventPayload
|
||||
|
||||
/** Verdict of the deterministic plan-grounding phase (design 2026-07-15 seam 1). */
|
||||
enum class PlanGroundingVerdict { PASS, RETURN_TO_ARCHITECT, CLARIFICATION_REQUIRED }
|
||||
|
||||
/**
|
||||
* The compiled plan was evaluated against recorded workspace facts BEFORE lock (design 2026-07-15
|
||||
* §"Seam 1: plan grounding before lock"). Deterministic, pure over the plan graph plus the session's
|
||||
* recorded [RepoMapComputedEvent] and [ProjectProfileBoundEvent] — no inference, no live FS read, so
|
||||
* replay reads the recorded verdict back (invariants #8/#9). A non-[PlanGroundingVerdict.PASS] verdict
|
||||
* blocks the lock and returns compact [findings] to the architect, so a doomed scaffold fails at stage
|
||||
* 0 rather than after downstream files accumulate.
|
||||
*
|
||||
* v1 grounds build prerequisites: a stage that will run a build/typecheck/test command against a
|
||||
* prerequisite (build manifest) that neither exists in the recorded repo map nor is produced by any
|
||||
* plan stage is ungrounded. Path/symbol-reference grounding (spec rows 2/3) needs a grounding-grade
|
||||
* symbol index and is deferred — those assumptions resolve to `unknown`, never `present`.
|
||||
*
|
||||
* [stateKey] pins the workspace snapshot (repo-map hash) the grounding was evaluated against.
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("PlanGroundingEvaluated")
|
||||
data class PlanGroundingEvaluatedEvent(
|
||||
val sessionId: SessionId,
|
||||
val planId: String,
|
||||
val stateKey: String,
|
||||
val verdict: PlanGroundingVerdict,
|
||||
val findings: List<String> = emptyList(),
|
||||
) : EventPayload
|
||||
|
||||
/** Outcome of the bounded LLM "are you sure?" reflection pass over a [CapabilityGapDetectedEvent]. */
|
||||
enum class CapabilityGapVerdict { RESOLVED, NEEDS_TOOL }
|
||||
|
||||
|
||||
@@ -168,3 +168,23 @@ data class RetrySalvageDecidedEvent(
|
||||
val decision: SalvageDecision,
|
||||
val rationale: String,
|
||||
) : EventPayload
|
||||
|
||||
/**
|
||||
* A stage repeatedly blocked on a missing build prerequisite (see repeatedBuildCriticalReferenceBlock,
|
||||
* design 2026-07-15 §#170) AND the stage both holds file_write and declares the path in-scope, so the
|
||||
* orchestrator grants it ONE dedicated bootstrap turn to create/repair that prerequisite — separately
|
||||
* budgeted, NOT charged against the normal stage retry counter. This marker records the grant: it caps
|
||||
* the bootstrap at one attempt per stage (a second block escalates to recovery) and scopes the
|
||||
* REFERENCE_EXISTS block window so historical blocks from before the grant don't re-trip the gate on
|
||||
* the fresh turn. Recorded (invariant #9) so replay reproduces the same bounded bootstrap.
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("BuildPrerequisiteBootstrapAttempted")
|
||||
data class BuildPrerequisiteBootstrapAttemptedEvent(
|
||||
val sessionId: SessionId,
|
||||
val stageId: StageId,
|
||||
// The build-critical workspace-relative path the stage is granted a turn to create/repair.
|
||||
val path: String,
|
||||
// The gate evidence (repeatedBuildCriticalReferenceBlock reason) that triggered the grant.
|
||||
val evidence: String,
|
||||
) : EventPayload
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
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
|
||||
|
||||
/**
|
||||
* The known-good workspace invariant (design 2026-07-15 §"Known-good workspace invariant", seam 2).
|
||||
* After a code/config-writing stage runs its deterministic build/test gate, the orchestrator records
|
||||
* ONE verification observation binding the [passed] result to the [stateKey] of the workspace that was
|
||||
* actually verified. The next implementation stage may treat the workspace as `known-good` only when
|
||||
* a passing observation's [stateKey] still equals the current recorded state key — a later write
|
||||
* changes the key, so a dirty workspace can never be mistaken for the state that passed.
|
||||
*
|
||||
* The [stateKey] is derived purely from the recorded FileWritten manifest (path → latest post-image
|
||||
* hash), so it is replay-safe: replay reads this event and the key back, never re-running [command]
|
||||
* or rescanning the filesystem (invariants #8/#9). [changedPaths] are the write-declaring stage's
|
||||
* paths at verification time; [expectation] is the deterministic build vocabulary (MODULE/PROJECT/
|
||||
* TESTS) that selected [command] — the model never chooses the truth test.
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("WorkspaceVerificationObserved")
|
||||
data class WorkspaceVerificationObservedEvent(
|
||||
val sessionId: SessionId,
|
||||
val stageId: StageId,
|
||||
val stateKey: String,
|
||||
val expectation: String,
|
||||
val command: String,
|
||||
val passed: Boolean,
|
||||
val changedPaths: List<String> = emptyList(),
|
||||
) : EventPayload
|
||||
@@ -65,6 +65,9 @@ import com.correx.core.events.events.RepoMapComputedEvent
|
||||
import com.correx.core.events.events.RetryAttemptedEvent
|
||||
import com.correx.core.events.events.RetrySalvageDecidedEvent
|
||||
import com.correx.core.events.events.FailureTicketOpenedEvent
|
||||
import com.correx.core.events.events.BuildPrerequisiteBootstrapAttemptedEvent
|
||||
import com.correx.core.events.events.WorkspaceVerificationObservedEvent
|
||||
import com.correx.core.events.events.PlanGroundingEvaluatedEvent
|
||||
import com.correx.core.events.events.OutsidePathAccessGrantedEvent
|
||||
import com.correx.core.events.events.WorkspaceStateObservedEvent
|
||||
import com.correx.core.events.events.RiskAssessedEvent
|
||||
@@ -158,6 +161,9 @@ val eventModule = SerializersModule {
|
||||
subclass(RetryAttemptedEvent::class)
|
||||
subclass(RetrySalvageDecidedEvent::class)
|
||||
subclass(FailureTicketOpenedEvent::class)
|
||||
subclass(BuildPrerequisiteBootstrapAttemptedEvent::class)
|
||||
subclass(WorkspaceVerificationObservedEvent::class)
|
||||
subclass(PlanGroundingEvaluatedEvent::class)
|
||||
subclass(OutsidePathAccessGrantedEvent::class)
|
||||
subclass(RefinementIterationEvent::class)
|
||||
subclass(RepoMapComputedEvent::class)
|
||||
|
||||
Reference in New Issue
Block a user