From 71aac8afc9f98042a3f6fbb6781a8e8c75d5d372 Mon Sep 17 00:00:00 2001 From: kami Date: Sun, 24 May 2026 22:36:59 +0400 Subject: [PATCH] feat(server-03): log unmapped events at DEBUG in DomainEventMapper Adds a file-private SLF4J logger and replaces the silent else->null branch with a debug log line that names the payload type, sessionId, and sequence. Test extended with a log-capture case that verifies exactly one DEBUG event is emitted containing the payload class name for unrecognised event types. --- .../apps/server/bridge/DomainEventMapper.kt | 13 ++++++- .../server/bridge/DomainEventMapperTest.kt | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt b/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt index f0e81ca0..4aaf83cf 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/bridge/DomainEventMapper.kt @@ -21,6 +21,9 @@ import com.correx.core.events.events.TransitionExecutedEvent import com.correx.core.events.events.WorkflowCompletedEvent import com.correx.core.events.events.WorkflowFailedEvent import com.correx.core.events.types.ArtifactId +import org.slf4j.LoggerFactory + +private val log = LoggerFactory.getLogger("DomainEventMapper") class DomainEventMapper(private val artifactStore: ArtifactStore = NoopArtifactStore) { suspend fun map(event: StoredEvent): ServerMessage? = @@ -138,7 +141,15 @@ suspend fun domainEventToServerMessage( ) is ApprovalRequestedEvent -> mapApprovalRequested(p, seq, sessionSequence) - else -> null + else -> { + log.debug( + "DomainEventMapper: unmapped payload type={} sessionId={} sequence={}", + p::class.simpleName, + event.metadata.sessionId, + event.sequence, + ) + null + } } } diff --git a/apps/server/src/test/kotlin/com/correx/apps/server/bridge/DomainEventMapperTest.kt b/apps/server/src/test/kotlin/com/correx/apps/server/bridge/DomainEventMapperTest.kt index 3a48976d..13d1945c 100644 --- a/apps/server/src/test/kotlin/com/correx/apps/server/bridge/DomainEventMapperTest.kt +++ b/apps/server/src/test/kotlin/com/correx/apps/server/bridge/DomainEventMapperTest.kt @@ -37,8 +37,15 @@ import com.correx.core.events.types.ValidationReportId import com.correx.core.inference.TokenUsage import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.core.LogEvent +import org.apache.logging.log4j.core.LoggerContext +import org.apache.logging.log4j.core.appender.AbstractAppender +import org.apache.logging.log4j.core.config.Property import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test class DomainEventMapperTest { @@ -368,4 +375,33 @@ class DomainEventMapperTest { val result = domainEventToServerMessage(event, noopStore, sessionSequence = 0L) assertNull(result) } + + private class TestAppender : AbstractAppender("TestCapture", null, null, true, Property.EMPTY_ARRAY) { + val events = mutableListOf() + override fun append(event: LogEvent) { + events.add(event.toImmutable()) + } + } + + @Test + fun `unmapped event emits debug log`(): Unit = runTest { + val ctx = LogManager.getContext(false) as LoggerContext + val logger = ctx.getLogger("DomainEventMapper") + val appender = TestAppender().also { it.start() } + logger.addAppender(appender) + val origLevel = logger.level + logger.level = Level.DEBUG + try { + val event = storedEvent(SessionStartedEvent(sessionId = sessionId)) + val result = domainEventToServerMessage(event, noopStore, sessionSequence = 0L) + assertNull(result) + assertEquals(1, appender.events.size) + assertEquals(Level.DEBUG, appender.events[0].level) + assertTrue(appender.events[0].message.formattedMessage.contains("SessionStartedEvent")) + } finally { + logger.removeAppender(appender) + appender.stop() + logger.level = origLevel + } + } }