feat(transitions): tasks_ready predicate for execution loop

New TasksReady condition driven by EvaluationContext.readyTaskCount,
fed at resolve time via a kernel-declared ReadyTaskCounter interface
implemented in apps/server over TaskService (keeps core:kernel
decoupled from core:tasks). Loops a graph while ready>0, exits at 0.
This commit is contained in:
2026-06-29 00:45:33 +04:00
parent d26f20c316
commit c1e4c7b25e
14 changed files with 164 additions and 1 deletions
@@ -61,7 +61,8 @@ class DefaultSessionOrchestrator(
private val compactionService: JournalCompactionService? = null,
artifactKindRegistry: ArtifactKindRegistry? = null,
repoKnowledgeRetriever: RepoKnowledgeRetriever? = null,
) : SessionOrchestrator(repositories, engines, artifactStore, decisionJournalRepository, artifactKindRegistry = artifactKindRegistry, repoKnowledgeRetriever = repoKnowledgeRetriever), ApprovalGateway {
readyTaskCounter: ReadyTaskCounter? = null,
) : SessionOrchestrator(repositories, engines, artifactStore, decisionJournalRepository, artifactKindRegistry = artifactKindRegistry, repoKnowledgeRetriever = repoKnowledgeRetriever, readyTaskCounter = readyTaskCounter), ApprovalGateway {
override val tokenizer: Tokenizer? = tokenizer
override val cancellations: ConcurrentHashMap<SessionId, AtomicBoolean> =
ConcurrentHashMap<SessionId, AtomicBoolean>()
@@ -0,0 +1,13 @@
package com.correx.core.kernel.orchestration
import com.correx.core.events.types.SessionId
/**
* How many tasks are ready to claim for a session's project, read at transition-resolution time
* (invariant #9: the observation is taken when the predicate runs). Implemented in apps/server over
* the task projection — core:kernel stays decoupled from core:tasks. Null injection ⇒ count 0, so
* the [com.correx.core.transitions.conditions.TasksReady] predicate is simply false.
*/
fun interface ReadyTaskCounter {
fun count(sessionId: SessionId): Int
}
@@ -187,6 +187,7 @@ abstract class SessionOrchestrator(
private val decisionJournalRenderer: DecisionJournalRenderer = DecisionJournalRenderer(),
private val artifactKindRegistry: ArtifactKindRegistry? = null,
private val repoKnowledgeRetriever: RepoKnowledgeRetriever? = null,
private val readyTaskCounter: ReadyTaskCounter? = null,
) {
private val log = LoggerFactory.getLogger(this::class.java)
private val eventStore: EventStore = repositories.eventStore
@@ -1856,6 +1857,7 @@ abstract class SessionOrchestrator(
currentStage = currentStageId,
artifacts = artifacts,
artifactContent = artifactContent,
readyTaskCount = readyTaskCounter?.count(sessionId) ?: 0,
)
return transitionResolver.resolve(graph, ctx)
}