fix(server): bind project profile on chat-session start
Chat sessions never emitted ProjectProfileBoundEvent — only the workflow path did — so router triage always saw a null profile and could not cite conventions or commands. Extract the binding from launchSessionRun into ServerModule.bindProjectProfile and call it from handleStartChatSession.
This commit is contained in:
@@ -41,6 +41,7 @@ import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
private val log = LoggerFactory.getLogger(ServerModule::class.java)
|
||||
@@ -220,35 +221,7 @@ class ServerModule(
|
||||
),
|
||||
)
|
||||
}
|
||||
// Bind the per-repo project profile (curated .correx/project.toml) as an event so
|
||||
// stages and replay read the recorded snapshot, never the live file (invariants #8/#9).
|
||||
val workspaceRoot = runCatching {
|
||||
sessionRepository.getSession(sessionId).state.boundWorkspace?.workspaceRoot
|
||||
}.getOrNull() ?: projectMemory?.repoRoot()
|
||||
workspaceRoot?.let { root ->
|
||||
val projectProfile = ProjectProfileLoader.load(root)
|
||||
if (!projectProfile.isEmpty()) {
|
||||
eventStore.append(
|
||||
NewEvent(
|
||||
metadata = EventMetadata(
|
||||
eventId = EventId(java.util.UUID.randomUUID().toString()),
|
||||
sessionId = sessionId,
|
||||
timestamp = Clock.System.now(),
|
||||
schemaVersion = 1,
|
||||
causationId = null,
|
||||
correlationId = null,
|
||||
),
|
||||
payload = ProjectProfileBoundEvent(
|
||||
sessionId = sessionId,
|
||||
workspaceRoot = root,
|
||||
about = projectProfile.about,
|
||||
conventions = projectProfile.conventions,
|
||||
commands = projectProfile.commands,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
bindProjectProfile(sessionId)
|
||||
runCatching {
|
||||
orchestrator.run(sessionId, graph, sessionConfig)
|
||||
// After a successful freestyle planning run, lock the plan and execute phase 2.
|
||||
@@ -290,6 +263,38 @@ class ServerModule(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the per-repo project profile (curated .correx/project.toml) as an event so stages,
|
||||
* router chat triage, and replay read the recorded snapshot, never the live file
|
||||
* (invariants #8/#9). Shared by the workflow path and the chat-session path.
|
||||
*/
|
||||
suspend fun bindProjectProfile(sessionId: SessionId) {
|
||||
val workspaceRoot = runCatching {
|
||||
sessionRepository.getSession(sessionId).state.boundWorkspace?.workspaceRoot
|
||||
}.getOrNull() ?: projectMemory?.repoRoot() ?: return
|
||||
val projectProfile = withContext(Dispatchers.IO) { ProjectProfileLoader.load(workspaceRoot) }
|
||||
if (projectProfile.isEmpty()) return
|
||||
eventStore.append(
|
||||
NewEvent(
|
||||
metadata = EventMetadata(
|
||||
eventId = EventId(java.util.UUID.randomUUID().toString()),
|
||||
sessionId = sessionId,
|
||||
timestamp = Clock.System.now(),
|
||||
schemaVersion = 1,
|
||||
causationId = null,
|
||||
correlationId = null,
|
||||
),
|
||||
payload = ProjectProfileBoundEvent(
|
||||
sessionId = sessionId,
|
||||
workspaceRoot = workspaceRoot,
|
||||
about = projectProfile.about,
|
||||
conventions = projectProfile.conventions,
|
||||
commands = projectProfile.commands,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun launchSessionResume(sessionId: SessionId, graph: com.correx.core.transitions.graph.WorkflowGraph) {
|
||||
activeSessionJobs.computeIfAbsent(sessionId) {
|
||||
moduleScope.launch {
|
||||
|
||||
@@ -379,6 +379,11 @@ class GlobalStreamHandler(private val module: ServerModule) {
|
||||
payload = ChatSessionStartedEvent(sessionId = sessionId),
|
||||
))
|
||||
|
||||
// Bind the per-repo project profile so router triage can cite conventions/commands.
|
||||
// Parity with launchSessionRun — chat sessions previously never bound a profile.
|
||||
runCatching { module.bindProjectProfile(sessionId) }
|
||||
.onFailure { log.warn("project profile binding failed for chat session={}: {}", sessionId.value, it.message) }
|
||||
|
||||
runCatching {
|
||||
module.routerFacade.onUserInput(sessionId, msg.text)
|
||||
}.onFailure {
|
||||
|
||||
Reference in New Issue
Block a user