diff --git a/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/CompileSurfaceParityTests.cs b/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/CompileSurfaceParityTests.cs
index 45af5064..5b86748e 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/CompileSurfaceParityTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests/Scripts/CompileSurfaceParityTests.cs
@@ -67,14 +67,44 @@ public class CompileSurfaceParityTests
///
/// The runtime script accessor type whose public methods are enumerated.
/// The compile-only mirror type that must cover those methods.
+ ///
+ /// Runtime method names that are public but NOT script-reachable and must therefore be absent
+ /// from the mirror (e.g. ScriptLogger.FlushDropped, called by the run launcher). Each
+ /// entry must exist on the runtime accessor and must NOT exist on the mirror, so a stale or
+ /// over-broad exclusion fails the theory instead of silently widening the hole (Gitea #57).
+ ///
[Theory]
[MemberData(nameof(AccessorMirrorPairs))]
public void CompileAccessorMirror_Covers_RuntimeAccessor_MethodArities(
- Type runtimeAccessor, Type compileMirror)
+ Type runtimeAccessor, Type compileMirror, string[] ignoredRuntimeMethods)
{
+ var ignored = new HashSet(ignoredRuntimeMethods, StringComparer.Ordinal);
var mirrorCounts = PublicInstanceMethodArityCounts(compileMirror);
var runtimeCounts = PublicInstanceMethodArityCounts(runtimeAccessor);
+ var staleExclusions = ignored
+ .Where(name => !runtimeCounts.Keys.Any(k => k.Name == name))
+ .OrderBy(name => name, StringComparer.Ordinal)
+ .ToList();
+ Assert.True(
+ staleExclusions.Count == 0,
+ $"Exclusion(s) {string.Join(", ", staleExclusions)} name no public method on runtime accessor "
+ + $"'{runtimeAccessor.Name}' — remove the stale entry from AccessorMirrorPairs.");
+
+ var exposedExclusions = ignored
+ .Where(name => mirrorCounts.Keys.Any(k => k.Name == name))
+ .OrderBy(name => name, StringComparer.Ordinal)
+ .ToList();
+ Assert.True(
+ exposedExclusions.Count == 0,
+ $"Excluded runtime method(s) {string.Join(", ", exposedExclusions)} are present on mirror "
+ + $"'{compileMirror.Name}'. An exclusion means the member is NOT script-reachable, so the "
+ + "mirror must not offer it — either drop it from the mirror or drop the exclusion.");
+
+ runtimeCounts = runtimeCounts
+ .Where(kvp => !ignored.Contains(kvp.Key.Name))
+ .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+
var shortfalls = runtimeCounts
.Where(kvp => mirrorCounts.GetValueOrDefault(kvp.Key) < kvp.Value)
.OrderBy(kvp => kvp.Key.Name, StringComparer.Ordinal)
@@ -99,27 +129,39 @@ public class CompileSurfaceParityTests
/// Runtime script-accessor type ↔ compile-surface mirror pairs guarded by
/// .
///
- /// The runtime accessor and compile mirror type pairs, one per theory case.
+ ///
+ /// The runtime accessor, compile mirror and ignored-runtime-method triples, one per theory case.
+ ///
public static IEnumerable