@@ -42,7 +42,7 @@ void setUp() {
4242 }
4343
4444 private DurableLogger createLogger (Mode mode , Suppression suppression ) {
45- when (mockExecutionManager .isReplaying ( )).thenReturn (mode == Mode .REPLAYING );
45+ when (mockExecutionManager .hasOperationsForContext ( null )).thenReturn (mode == Mode .REPLAYING );
4646 return new DurableLogger (mockLogger , createDurableContext (REQUEST_ID , suppression ));
4747 }
4848
@@ -104,7 +104,7 @@ void setsExecutionMdcInConstructor() {
104104 void setStepThreadPropertiesSetsMdc () {
105105 try (MockedStatic <MDC > mdcMock = mockStatic (MDC .class )) {
106106 mdcMock .clearInvocations ();
107- when (mockExecutionManager .isReplaying ( )).thenReturn (false );
107+ when (mockExecutionManager .hasOperationsForContext ( null )).thenReturn (false );
108108 var logger = new DurableLogger (
109109 mockLogger ,
110110 createDurableContext (REQUEST_ID , Suppression .ENABLED )
@@ -130,13 +130,17 @@ void clearThreadPropertiesRemovesMdc() {
130130
131131 @ Test
132132 void replayModeTransitionAllowsSubsequentLogs () {
133- when (mockExecutionManager .isReplaying ()).thenReturn (true , false );
134- var logger = new DurableLogger (mockLogger , createDurableContext (REQUEST_ID , Suppression .ENABLED ));
133+ when (mockExecutionManager .hasOperationsForContext (null )).thenReturn (true );
134+ var durableContext = createDurableContext (REQUEST_ID , Suppression .ENABLED );
135+ var logger = new DurableLogger (mockLogger , durableContext );
135136
136137 // During replay - suppressed
137138 logger .info ("suppressed" );
138139 verify (mockLogger , never ()).info (anyString (), any (Object [].class ));
139140
141+ // Transition to execution mode at per-context level
142+ durableContext .setExecutionMode ();
143+
140144 // After transition to execution mode - logged
141145 logger .info ("logged after transition" );
142146 verify (mockLogger ).info (eq ("logged after transition" ), any (Object [].class ));
@@ -163,10 +167,40 @@ void allLogLevelsDelegateCorrectly() {
163167 verify (mockLogger ).error ("error with exception" , exception );
164168 }
165169
170+ @ Test
171+ void concurrentContextsHaveIndependentReplayState () {
172+ // Simulate two child contexts: one still replaying, one already executing
173+ when (mockExecutionManager .hasOperationsForContext (null )).thenReturn (true );
174+ when (mockExecutionManager .hasOperationsForContext ("child-a" )).thenReturn (false );
175+ when (mockExecutionManager .hasOperationsForContext ("child-b" )).thenReturn (true );
176+
177+ var rootContext = createDurableContext (REQUEST_ID , Suppression .ENABLED );
178+ var childA = rootContext .createChildContext ("child-a" , "branch-a" , false );
179+ var childB = rootContext .createChildContext ("child-b" , "branch-b" , false );
180+
181+ var loggerForA = mock (Logger .class );
182+ var loggerForB = mock (Logger .class );
183+ var durableLoggerA = new DurableLogger (loggerForA , childA );
184+ var durableLoggerB = new DurableLogger (loggerForB , childB );
185+
186+ // Child A is in execution mode — logs should pass through
187+ durableLoggerA .info ("from branch A" );
188+ verify (loggerForA ).info (eq ("from branch A" ), any (Object [].class ));
189+
190+ // Child B is still replaying — logs should be suppressed
191+ durableLoggerB .info ("from branch B" );
192+ verify (loggerForB , never ()).info (anyString (), any (Object [].class ));
193+
194+ // After child B transitions, its logs should pass through
195+ childB .setExecutionMode ();
196+ durableLoggerB .info ("branch B after transition" );
197+ verify (loggerForB ).info (eq ("branch B after transition" ), any (Object [].class ));
198+ }
199+
166200 @ Test
167201 void handlesNullRequestId () {
168202 try (MockedStatic <MDC > mdcMock = mockStatic (MDC .class )) {
169- when (mockExecutionManager .isReplaying ( )).thenReturn (false );
203+ when (mockExecutionManager .hasOperationsForContext ( null )).thenReturn (false );
170204 new DurableLogger (mockLogger , createDurableContext (null , Suppression .DISABLED ));
171205
172206 mdcMock .verify (() -> MDC .put (DurableLogger .MDC_EXECUTION_ARN , EXECUTION_ARN ));
0 commit comments