diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventVerdictInvalidationTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventVerdictInvalidationTests.cs
index f20a6ea7a..f820e5f75 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventVerdictInvalidationTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/FolderEventVerdictInvalidationTests.cs
@@ -167,6 +167,55 @@ public sealed class FolderEventVerdictInvalidationTests
"MonitoredNode2.InvalidatePermissionCaches() is gone — re-check InvalidateFolderEventVerdicts against the new SDK");
}
+ ///
+ /// Gitea #838 item 3: an event on a folder that names no live condition (none is produced today — model-change and
+ /// rejected-write audits go to the Server object) is WITHHELD under enforcement, fail closed, and delivered with
+ /// the flag off (the SDK's own type + SourceNode check only). Positive controls: the same event reaches the same
+ /// item with enforcement off, and a condition event reaches it with enforcement on.
+ ///
+ [Fact]
+ public async Task A_non_condition_event_on_a_folder_is_withheld_under_enforcement_and_delivered_without_it()
+ {
+ var ct = TestContext.Current.CancellationToken;
+ await using var rig = await ServerEventRig.StartAsync("Folder838NonCondition", encrypted: false, ct);
+ rig.KeyRoles = [];
+ rig.MaterialiseNative();
+ rig.Enforce(false, [], ServerEventRig.EquipmentGrant(EqA, NodePermissions.ReadOnly));
+
+ using var session = await rig.ConnectAsync(anonymous: true, ct);
+ var events = new RecordedEvents();
+ var subscription = await RecordedEvents.SubscribeAsync(session, events, ct);
+ var onA = RecordedEvents.AddEventItem(subscription, ServerEventRig.UnsNodeId(session, EqA));
+ await subscription.ApplyChangesAsync(ct);
+ onA.Status.Error.ShouldBeNull();
+
+ var folder = rig.Nm.FindPredefinedNode(ServerEventRig.UnsNodeId(session, EqA)).ShouldNotBeNull();
+ void ReportPlainEvent(string message)
+ {
+ var e = new BaseEventState(null);
+ lock (rig.Nm.Lock)
+ {
+ e.Initialize(rig.Nm.SystemContext, folder, EventSeverity.Low, new LocalizedText(message));
+ folder.ReportEvent(rig.Nm.SystemContext, e);
+ }
+ }
+
+ ReportPlainEvent("plain-off");
+ await RecordedEvents.WaitUntilAsync(() => events.Has(onA, "plain-off"));
+
+ rig.Enforce(true, [], ServerEventRig.EquipmentGrant(EqA, NodePermissions.ReadOnly));
+ rig.Project(native: true, State("cond-on"));
+ await RecordedEvents.WaitUntilAsync(() => events.Has(onA, "cond-on"));
+
+ ReportPlainEvent("plain-on");
+ rig.Project(native: true, State("cond-on-2"));
+ await RecordedEvents.WaitUntilAsync(() => events.Has(onA, "cond-on-2"));
+ await Task.Delay(TimeSpan.FromMilliseconds(700), ct);
+ events.Has(onA, "plain-on").ShouldBeFalse("a non-condition event on a folder fails closed under enforcement");
+
+ await session.CloseAsync(ct);
+ }
+
private static AlarmConditionSnapshot State(string message) =>
new(true, false, false, true, AlarmShelvingKind.Unshelved, 700, message);