diff --git a/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs b/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs
index 3fe6f13..05b9919 100644
--- a/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs
+++ b/src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs
@@ -643,6 +643,13 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
return new IndirectLayoutResult(opaqueCount, transparentCount, opaqueCount * DrawCommandStride);
}
+ ///
+ /// Public test shim for . Locks in the N.5 Decision 2
+ /// translucency partition: Opaque + ClipMap → opaque indirect; AlphaBlend +
+ /// Additive + InvAlpha → transparent indirect.
+ ///
+ public static bool IsOpaquePublic(TranslucencyKind t) => IsOpaque(t);
+
private static bool IsOpaque(TranslucencyKind t)
=> t == TranslucencyKind.Opaque || t == TranslucencyKind.ClipMap;
diff --git a/tests/AcDream.Core.Tests/Rendering/Wb/WbDrawDispatcherTranslucencyTests.cs b/tests/AcDream.Core.Tests/Rendering/Wb/WbDrawDispatcherTranslucencyTests.cs
new file mode 100644
index 0000000..f79fb09
--- /dev/null
+++ b/tests/AcDream.Core.Tests/Rendering/Wb/WbDrawDispatcherTranslucencyTests.cs
@@ -0,0 +1,25 @@
+using AcDream.App.Rendering.Wb;
+using AcDream.Core.Meshing;
+using Xunit;
+
+namespace AcDream.Core.Tests.Rendering.Wb;
+
+///
+/// Locks in the N.5 translucency partition contract (spec Decision 2).
+/// If the partition drifts, the dispatcher's opaque + transparent indirect
+/// passes will silently render the wrong groups in the wrong pass — visible
+/// regression that's hard to spot in code review.
+///
+public sealed class WbDrawDispatcherTranslucencyTests
+{
+ [Theory]
+ [InlineData(TranslucencyKind.Opaque, true)]
+ [InlineData(TranslucencyKind.ClipMap, true)]
+ [InlineData(TranslucencyKind.AlphaBlend, false)]
+ [InlineData(TranslucencyKind.Additive, false)]
+ [InlineData(TranslucencyKind.InvAlpha, false)]
+ public void IsOpaque_PartitionsByKind(TranslucencyKind kind, bool expected)
+ {
+ Assert.Equal(expected, WbDrawDispatcher.IsOpaquePublic(kind));
+ }
+}