From a2bf976a13cdd756cf675bc626c0777fe3adf38a Mon Sep 17 00:00:00 2001 From: kami Date: Tue, 21 Jul 2026 01:48:45 +0400 Subject: [PATCH] fix(server): unify session workspace root (#266) --- apps/server/AGENTS.md | 2 +- .../com/correx/apps/server/BootWorkspace.kt | 6 --- .../kotlin/com/correx/apps/server/Main.kt | 2 +- .../com/correx/apps/server/ServerModule.kt | 40 +++++++++---------- .../memory/ArchitectContradictionChecker.kt | 16 ++++---- .../server/memory/ProjectMemoryService.kt | 3 -- .../correx/apps/server/BootWorkspaceTest.kt | 12 ------ .../ArchitectContradictionCheckerTest.kt | 20 +++++++--- .../ProjectMemoryServiceObservationTest.kt | 6 +-- .../memory/ProjectMemoryServiceReuseTest.kt | 7 ++-- .../server/memory/ProjectMemoryServiceTest.kt | 4 +- .../com/correx/core/config/ConfigLoader.kt | 1 - .../com/correx/core/config/CorrexConfig.kt | 3 +- .../correx/core/config/CorrexConfigWriter.kt | 1 - .../correx/core/config/ConfigLoaderTest.kt | 3 -- .../core/config/CorrexConfigWriterTest.kt | 2 +- .../kotlin/RepoMapReuseIntegrationTest.kt | 2 +- 17 files changed, 55 insertions(+), 75 deletions(-) diff --git a/apps/server/AGENTS.md b/apps/server/AGENTS.md index fd5a36c0..bffc26b8 100644 --- a/apps/server/AGENTS.md +++ b/apps/server/AGENTS.md @@ -21,7 +21,7 @@ All sources under `apps/server/src/`. - `GET /metrics/tool-reliability` — per-model tool-call validity across the event log (`ToolReliabilityInspectionService`); groundwork for capability-aware routing - Optional `[git]` transport creates `run/` from a server-local checkout and pushes it at terminal state; clients review with ordinary Git and never supply a remote URL as `cwd`. - Repo-map L3 embeddings use bounded, recorded source descriptors (module/package, imports, leading purpose comment, symbols); raw file bodies are never embedded. Their versioned `repomap:v2` namespace forces a one-time re-embed when the semantic document format changes. -- At boot, `tools.workspace_root` is the authoritative tool jail and project-observation root. A configured `tools.working_dir` may only remain distinct when it is contained by that root; an outside value is clamped to `workspace_root`. Project memory and repo-map indexing are also rebound to `workspace_root`, so a stale `[project].root` cannot inject files from outside the session workspace. +- At boot, `tools.workspace_root` is the authoritative default tool jail. Every session records its own resolved workspace binding; repo maps, project memory, profile/instruction snapshots, and git run branches use that binding and skip unbound sessions. `[project]` never supplies a workspace root. ### WebSocket protocol (`/ws`) - **ServerMessage** (server → client): sealed hierarchy — `SessionMessage` (event-derived, carries `sequence` + `sessionSequence`) and `NonEventMessage` (control/infra). Variants include session lifecycle, approval requests, clarification requests, narration, proposed workflows, health/metrics pushes. diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/BootWorkspace.kt b/apps/server/src/main/kotlin/com/correx/apps/server/BootWorkspace.kt index 7cf22703..e9160e9b 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/BootWorkspace.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/BootWorkspace.kt @@ -1,6 +1,5 @@ package com.correx.apps.server -import com.correx.core.config.ProjectConfig import java.nio.file.Path internal data class BootWorkspace( @@ -28,8 +27,3 @@ internal fun resolveBootWorkspace( workingDirWasClamped = !workingDirIsContained, ) } - -/** Keep repo-map observation and L3 project memory inside the authoritative boot workspace. */ -internal fun ProjectConfig.boundToWorkspace(workspaceRoot: Path): ProjectConfig = copy( - root = workspaceRoot.toAbsolutePath().normalize().toString(), -) diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt b/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt index 2099075b..6f04420a 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt @@ -590,7 +590,7 @@ fun main() { fun buildProjectMemory(cfg: CorrexConfig): com.correx.apps.server.memory.ProjectMemoryService? = if (cfg.project.enabled) { com.correx.apps.server.memory.ProjectMemoryService( - config = cfg.project.boundToWorkspace(workspaceRoot), + config = cfg.project, embedder = embedder, l3MemoryStore = l3MemoryStore, journalRepository = decisionJournalRepository, diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/ServerModule.kt b/apps/server/src/main/kotlin/com/correx/apps/server/ServerModule.kt index 6ac36c11..31f37a49 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/ServerModule.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/ServerModule.kt @@ -278,7 +278,8 @@ class ServerModule( event: ArtifactCreatedEvent, ): PossibleContradictionFlaggedEvent? { val decisionText = resolveArchitectDecisionText(event) ?: return null - val flag = checker.check(event.sessionId, event.stageId, decisionText) ?: return null + val workspaceRoot = sessionWorkspaceRoot(event.sessionId) ?: return null + val flag = checker.check(event.sessionId, event.stageId, decisionText, workspaceRoot) ?: return null eventStore.append( NewEvent( metadata = EventMetadata( @@ -379,12 +380,13 @@ class ServerModule( withSessionContext(sessionId) { // Record the repo map + seed prior-session memory before the run so stages // see both in context. - projectMemory?.let { pm -> - val root = sessionWorkspaceRoot(sessionId) - runCatching { - pm.observeAndRecord(sessionId, root) - pm.indexAndRecord(sessionId, root) - pm.retrieveAndSeed(sessionId, root) + sessionWorkspaceRoot(sessionId)?.let { root -> + projectMemory?.let { pm -> + runCatching { + pm.observeAndRecord(sessionId, root) + pm.indexAndRecord(sessionId, root) + pm.retrieveAndSeed(sessionId, root) + } } } // Bind operator profile snapshot as an event so replay reads the recorded @@ -417,7 +419,9 @@ class ServerModule( val result = orchestrator.run(sessionId, graph, sessionConfig) freestyleHandoff(sessionId, graph, result) // Distil this run's decisions into durable project memory on completion. - projectMemory?.let { pm -> pm.persist(sessionId, sessionWorkspaceRoot(sessionId)) } + sessionWorkspaceRoot(sessionId)?.let { root -> + projectMemory?.let { pm -> pm.persist(sessionId, root) } + } // Propose learned profile adaptations based on session journal (opt-in, never auto-applied). operatorProfile?.let { profile -> profileAdaptationService?.let { svc -> @@ -426,7 +430,7 @@ class ServerModule( } } } - val workspaceRoot = sessionConfig.workspace?.workspaceRoot + val workspaceRoot = sessionWorkspaceRoot(sessionId)?.let(java.nio.file.Path::of) if (gitRunBranchTransport != null && workspaceRoot != null) { gitRunBranchTransport.onRunBranch(sessionId, workspaceRoot) { runAndFinalize() } } else { @@ -501,19 +505,15 @@ class ServerModule( */ /** * The session's bound workspace root — the same one the tool jail and [SessionWorkspaceBoundEvent] - * use. The repo-map/index/L3-memory pipeline MUST key off this, not [ProjectMemoryService.repoRoot] - * (a session-independent config/cwd default): when they diverge the repo map is computed for a - * different tree than the session operates in, so grounding "proves" real paths absent - * (session 5fe538f5, 2026-07-19). Falls back to the server default only when unbound. + * use. Repo-scoped work must skip unbound sessions: a server cwd is not a session fact and + * cannot safely stand in for the recorded workspace binding. */ - private fun sessionWorkspaceRoot(sessionId: SessionId): String = + private fun sessionWorkspaceRoot(sessionId: SessionId): String? = runCatching { sessionRepository.getSession(sessionId).state.boundWorkspace?.workspaceRoot } - .getOrNull() ?: projectMemory?.repoRoot() ?: "." + .getOrNull() suspend fun bindProjectProfile(sessionId: SessionId) { - val workspaceRoot = runCatching { - sessionRepository.getSession(sessionId).state.boundWorkspace?.workspaceRoot - }.getOrNull() ?: projectMemory?.repoRoot() ?: return + val workspaceRoot = sessionWorkspaceRoot(sessionId) ?: return val projectProfile = withContext(Dispatchers.IO) { ProjectProfileLoader.load(workspaceRoot) } if (projectProfile.isEmpty()) return eventStore.append( @@ -543,9 +543,7 @@ class ServerModule( * live file (invariants #8/#9). Mirrors [bindProjectProfile]. */ suspend fun bindAgentInstructions(sessionId: SessionId) { - val workspaceRoot = runCatching { - sessionRepository.getSession(sessionId).state.boundWorkspace?.workspaceRoot - }.getOrNull() ?: projectMemory?.repoRoot() ?: return + val workspaceRoot = sessionWorkspaceRoot(sessionId) ?: return val instructions = withContext(Dispatchers.IO) { AgentInstructionsLoader.load(workspaceRoot) } if (instructions.isEmpty()) return eventStore.append( diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/memory/ArchitectContradictionChecker.kt b/apps/server/src/main/kotlin/com/correx/apps/server/memory/ArchitectContradictionChecker.kt index 3d1e4dfe..1a71cfd1 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/memory/ArchitectContradictionChecker.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/memory/ArchitectContradictionChecker.kt @@ -16,18 +16,16 @@ import com.correx.core.talkie.l3.L3Query * emits the flag without ever halting or failing the stage. * * Namespace convention: distilled decision-journal lines are persisted into L3 by - * [ProjectMemoryService] under `turnId = "project:"` (trailing-`:` delimiter). This is - * the only decision-bearing L3 namespace that exists today, so [decisionNamespacePrefix] defaults - * to `"project:"` — a `startsWith` prefix, matching the trailing-`:` delimiter convention used by - * [L3RepoKnowledgeRetriever]'s versioned `"repomap:v2::"` filter. Hits are also constrained to PRIOR - * sessions (`entry.sessionId != sessionId`) so the architect never flags its own in-flight run. + * [ProjectMemoryService] under `turnId = "project:"`. The exact tag is derived + * from the session's recorded workspace binding so a decision can never cross workspace boundaries. + * Hits are also constrained to PRIOR sessions (`entry.sessionId != sessionId`) so the architect + * never flags its own in-flight run. */ class ArchitectContradictionChecker( private val embedder: Embedder, private val l3MemoryStore: L3MemoryStore, private val k: Int = DEFAULT_K, private val scoreThreshold: Double = DEFAULT_SCORE_THRESHOLD, - private val decisionNamespacePrefix: String = DEFAULT_DECISION_NAMESPACE_PREFIX, ) { /** * @return a [PossibleContradictionFlaggedEvent] listing related prior decisions, or null when @@ -37,11 +35,12 @@ class ArchitectContradictionChecker( sessionId: SessionId, stageId: StageId, decisionText: String, + workspaceRoot: String, ): PossibleContradictionFlaggedEvent? { if (decisionText.isBlank()) return null val vector = embedder.embed(decisionText) val related = l3MemoryStore.query(L3Query(vector = vector, k = k * RETRIEVAL_OVERSAMPLE_FACTOR)) - .filter { it.entry.turnId.startsWith(decisionNamespacePrefix) } + .filter { it.entry.turnId == projectMemoryTag(workspaceRoot) } .filter { it.entry.sessionId != sessionId } .filter { it.score >= scoreThreshold } .take(k) @@ -64,7 +63,8 @@ class ArchitectContradictionChecker( companion object { const val DEFAULT_K = 5 const val DEFAULT_SCORE_THRESHOLD = 0.75 - const val DEFAULT_DECISION_NAMESPACE_PREFIX = "project:" private const val RETRIEVAL_OVERSAMPLE_FACTOR = 4 + + fun projectMemoryTag(workspaceRoot: String): String = "project:$workspaceRoot" } } diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/memory/ProjectMemoryService.kt b/apps/server/src/main/kotlin/com/correx/apps/server/memory/ProjectMemoryService.kt index 1957374d..ece3fe0c 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/memory/ProjectMemoryService.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/memory/ProjectMemoryService.kt @@ -52,9 +52,6 @@ class ProjectMemoryService( private fun tag(repoRoot: String) = "project:$repoRoot" - /** Resolved repo-root key: configured [ProjectConfig.root], else the working dir. */ - fun repoRoot(): String = config.root.ifBlank { System.getProperty("user.dir") ?: "." } - /** * Walk [repoRoot] and record the ranked file/symbol map as a [RepoMapComputedEvent] once * per session. The full map is recorded (the log); only a top-K slice is injected into diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/BootWorkspaceTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/BootWorkspaceTest.kt index b0d785cf..e822f327 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/BootWorkspaceTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/BootWorkspaceTest.kt @@ -1,6 +1,5 @@ package com.correx.apps.server -import com.correx.core.config.ProjectConfig import java.nio.file.Path import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -47,15 +46,4 @@ class BootWorkspaceTest { assertFalse(resolved.workingDirWasClamped) } - @Test - fun `project memory root follows the authoritative workspace root`() { - val configured = ProjectConfig( - enabled = true, - root = "/home/user/repo", - ) - - val resolved = configured.boundToWorkspace(Path.of("/tmp/audition/../audition")) - - assertEquals("/tmp/audition", resolved.root) - } } diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ArchitectContradictionCheckerTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ArchitectContradictionCheckerTest.kt index 163b79e7..de01ac90 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ArchitectContradictionCheckerTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ArchitectContradictionCheckerTest.kt @@ -52,7 +52,7 @@ class ArchitectContradictionCheckerTest { ) val checker = ArchitectContradictionChecker(ContradictionOnesEmbedder(), store) - val flag = checker.check(newSession, stageId, "Use Postgres for the event store.") + val flag = checker.check(newSession, stageId, "Use Postgres for the event store.", "/repo") assertTrue(flag != null, "expected a flag") assertEquals(newSession, flag!!.sessionId) @@ -69,7 +69,7 @@ class ArchitectContradictionCheckerTest { fun `returns null when there are no hits`() = runBlocking { val checker = ArchitectContradictionChecker(ContradictionOnesEmbedder(), CannedL3MemoryStore(emptyList())) - assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.")) + assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.", "/repo")) } @Test @@ -79,7 +79,7 @@ class ArchitectContradictionCheckerTest { ) val checker = ArchitectContradictionChecker(ContradictionOnesEmbedder(), store, scoreThreshold = 0.75) - assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.")) + assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.", "/repo")) } @Test @@ -92,7 +92,17 @@ class ArchitectContradictionCheckerTest { ) val checker = ArchitectContradictionChecker(ContradictionOnesEmbedder(), store) - assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.")) + assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.", "/repo")) + } + + @Test + fun `filters out decisions from another workspace`() = runBlocking { + val store = CannedL3MemoryStore( + listOf(hit("Other workspace decision.", score = 0.95f, turnId = "project:/other-repo")), + ) + val checker = ArchitectContradictionChecker(ContradictionOnesEmbedder(), store) + + assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.", "/repo")) } @Test @@ -102,6 +112,6 @@ class ArchitectContradictionCheckerTest { ) val checker = ArchitectContradictionChecker(ContradictionOnesEmbedder(), store) - assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.")) + assertNull(checker.check(newSession, stageId, "Use Postgres for the event store.", "/repo")) } } diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceObservationTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceObservationTest.kt index 846457e0..4cf3f4ac 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceObservationTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceObservationTest.kt @@ -44,7 +44,7 @@ class ProjectMemoryServiceObservationTest { @Test fun `probe success emits WorkspaceStateObservedEvent`(): Unit = runBlocking { val es = InMemoryEventStore() - val config = ProjectConfig(enabled = true, root = "/repo") + val config = ProjectConfig(enabled = true) val sessionId = SessionId("session-obs-1") service(config, es, WorkspaceState("git:abc123", "git", "main", false)) @@ -63,7 +63,7 @@ class ProjectMemoryServiceObservationTest { @Test fun `probe null emits no event`(): Unit = runBlocking { val es = InMemoryEventStore() - val config = ProjectConfig(enabled = true, root = "/repo") + val config = ProjectConfig(enabled = true) val sessionId = SessionId("session-obs-2") service(config, es, null).observeAndRecord(sessionId, "/repo") @@ -76,7 +76,7 @@ class ProjectMemoryServiceObservationTest { @Test fun `disabled config skips observation`(): Unit = runBlocking { val es = InMemoryEventStore() - val config = ProjectConfig(enabled = false, root = "/repo") + val config = ProjectConfig(enabled = false) val sessionId = SessionId("session-obs-3") service(config, es, WorkspaceState("git:abc123", "git", "main", false)) diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceReuseTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceReuseTest.kt index 3f3e58c4..0673875f 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceReuseTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceReuseTest.kt @@ -40,9 +40,8 @@ class ProjectMemoryServiceReuseTest { l3: InMemoryL3MemoryStore, indexer: CountingIndexer, probe: WorkspaceStateProbe, - root: String = "/repo", ) = ProjectMemoryService( - config = ProjectConfig(enabled = true, root = root), + config = ProjectConfig(enabled = true), embedder = ConstantEmbedderReuse(), l3MemoryStore = l3, journalRepository = DefaultDecisionJournalRepository( @@ -136,9 +135,9 @@ class ProjectMemoryServiceReuseTest { val repoEntries = listOf(RepoMapEntry(path = "src/Repo.kt", score = 1.0, symbols = listOf("RepoClass"))) val repo2Entries = listOf(RepoMapEntry(path = "src/Repo2.kt", score = 1.0, symbols = listOf("Repo2Class"))) - service(es, l3, CountingIndexer(repoEntries), probe, root = "/repo") + service(es, l3, CountingIndexer(repoEntries), probe) .indexAndRecord(SessionId("session-collide-repo"), "/repo") - service(es, l3, CountingIndexer(repo2Entries), probe, root = "/repo2") + service(es, l3, CountingIndexer(repo2Entries), probe) .indexAndRecord(SessionId("session-collide-repo2"), "/repo2") // existsByTurnIdPrefix with the delimiter must not match the other root. diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceTest.kt index ae6d473b..134ad736 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/memory/ProjectMemoryServiceTest.kt @@ -58,7 +58,7 @@ class ProjectMemoryServiceTest { fun `decisions persisted in one session are retrieved and seeded in the next`(): Unit = runBlocking { val eventStore = InMemoryEventStore() val l3 = InMemoryL3MemoryStore() - val config = ProjectConfig(enabled = true, root = "/repo", memoryK = 5) + val config = ProjectConfig(enabled = true, memoryK = 5) val sessionA = SessionId("A") store(sessionA, SteeringNoteAddedEvent(sessionA, "use jwt for auth"), eventStore) @@ -85,7 +85,7 @@ class ProjectMemoryServiceTest { fun `disabled project memory is a no-op`(): Unit = runBlocking { val eventStore = InMemoryEventStore() val l3 = InMemoryL3MemoryStore() - val config = ProjectConfig(enabled = false, root = "/repo") + val config = ProjectConfig(enabled = false) val sessionA = SessionId("A") store(sessionA, SteeringNoteAddedEvent(sessionA, "secret"), eventStore) diff --git a/core/config/src/main/kotlin/com/correx/core/config/ConfigLoader.kt b/core/config/src/main/kotlin/com/correx/core/config/ConfigLoader.kt index b3e17da5..2003df82 100644 --- a/core/config/src/main/kotlin/com/correx/core/config/ConfigLoader.kt +++ b/core/config/src/main/kotlin/com/correx/core/config/ConfigLoader.kt @@ -679,7 +679,6 @@ object ConfigLoader { val projectSection = sections["project"] ?: emptyMap() val project = ProjectConfig( enabled = asBoolean(projectSection["enabled"], false), - root = asString(projectSection["root"], ""), memoryK = asInt(projectSection["memory_k"], DEFAULT_PROJECT_MEMORY_K), maxDepth = asInt(projectSection["max_depth"], DEFAULT_PROJECT_MAX_DEPTH), ignoreGlobs = asStringList(projectSection["ignore_globs"]).ifEmpty { ProjectConfig.DEFAULT_IGNORES }, diff --git a/core/config/src/main/kotlin/com/correx/core/config/CorrexConfig.kt b/core/config/src/main/kotlin/com/correx/core/config/CorrexConfig.kt index 2bfa809f..9aaed1a7 100644 --- a/core/config/src/main/kotlin/com/correx/core/config/CorrexConfig.kt +++ b/core/config/src/main/kotlin/com/correx/core/config/CorrexConfig.kt @@ -146,12 +146,11 @@ data class PersonalizationConfig( /** * Project-scoped, cross-session memory. When [enabled], the decision journal is distilled * to durable per-repo memory at session end and retrieved (top-[memoryK]) at session start. - * [root] is the repo root key; empty means the current working directory. + * The repository key is always the session's recorded bound workspace, never configuration. */ @Serializable data class ProjectConfig( val enabled: Boolean = false, - val root: String = "", val memoryK: Int = 5, val maxDepth: Int = 4, val ignoreGlobs: List = DEFAULT_IGNORES, diff --git a/core/config/src/main/kotlin/com/correx/core/config/CorrexConfigWriter.kt b/core/config/src/main/kotlin/com/correx/core/config/CorrexConfigWriter.kt index 941de847..1de2f534 100644 --- a/core/config/src/main/kotlin/com/correx/core/config/CorrexConfigWriter.kt +++ b/core/config/src/main/kotlin/com/correx/core/config/CorrexConfigWriter.kt @@ -122,7 +122,6 @@ object CorrexConfigWriter { b.section("project") b.kv("enabled", cfg.project.enabled) - b.kv("root", str(cfg.project.root)) b.kv("memory_k", cfg.project.memoryK) b.kv("max_depth", cfg.project.maxDepth) b.kv("inject_top_k", cfg.project.injectTopK) diff --git a/core/config/src/test/kotlin/com/correx/core/config/ConfigLoaderTest.kt b/core/config/src/test/kotlin/com/correx/core/config/ConfigLoaderTest.kt index 729df866..323456f5 100644 --- a/core/config/src/test/kotlin/com/correx/core/config/ConfigLoaderTest.kt +++ b/core/config/src/test/kotlin/com/correx/core/config/ConfigLoaderTest.kt @@ -189,7 +189,6 @@ class ConfigLoaderTest { val toml = """ [project] enabled = true - root = "/home/me/repo" memory_k = 8 """.trimIndent() @@ -199,7 +198,6 @@ class ConfigLoaderTest { val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig assertEquals(true, result.project.enabled) - assertEquals("/home/me/repo", result.project.root) assertEquals(8, result.project.memoryK) } @@ -216,7 +214,6 @@ class ConfigLoaderTest { val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig assertEquals(false, result.project.enabled) - assertEquals("", result.project.root) assertEquals(5, result.project.memoryK) } diff --git a/core/config/src/test/kotlin/com/correx/core/config/CorrexConfigWriterTest.kt b/core/config/src/test/kotlin/com/correx/core/config/CorrexConfigWriterTest.kt index 048d074d..ce9e9355 100644 --- a/core/config/src/test/kotlin/com/correx/core/config/CorrexConfigWriterTest.kt +++ b/core/config/src/test/kotlin/com/correx/core/config/CorrexConfigWriterTest.kt @@ -36,7 +36,7 @@ class CorrexConfigWriterTest { narration = NarrationSettings(temperature = 0.1, topP = 0.95, maxTokens = 256, maxPerRun = 3), ), personalization = PersonalizationConfig(enabled = true, learn = true), - project = ProjectConfig(enabled = true, root = "/repo", memoryK = 8, maxDepth = 6, injectTopK = 40), + project = ProjectConfig(enabled = true, memoryK = 8, maxDepth = 6, injectTopK = 40), git = GitConfig(enabled = true, remote = "gitea", baseBranch = "develop", author = "Correx "), modelsSettings = ModelsSettings(defaultModel = "m1", host = "0.0.0.0", port = 10001), orchestration = OrchestrationKnobs(stageTimeoutMs = 90_000, journalCompactionTokenThreshold = 12_000), diff --git a/testing/integration/src/test/kotlin/RepoMapReuseIntegrationTest.kt b/testing/integration/src/test/kotlin/RepoMapReuseIntegrationTest.kt index 03db6b51..5880dbb0 100644 --- a/testing/integration/src/test/kotlin/RepoMapReuseIntegrationTest.kt +++ b/testing/integration/src/test/kotlin/RepoMapReuseIntegrationTest.kt @@ -127,7 +127,7 @@ class RepoMapReuseIntegrationTest { embedder: Embedder, probe: FakeWorkspaceStateProbe, ) = ProjectMemoryService( - config = ProjectConfig(enabled = true, root = repoRoot), + config = ProjectConfig(enabled = true), embedder = embedder, l3MemoryStore = l3, journalRepository = DefaultDecisionJournalRepository(