diff --git a/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs b/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs
new file mode 100644
index 00000000..5e5f1228
--- /dev/null
+++ b/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs
@@ -0,0 +1,198 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using AcDream.App.Rendering;
+using DatReaderWriter;
+using DatReaderWriter.Options;
+using Xunit;
+using Xunit.Abstractions;
+using DatLandBlockInfo = DatReaderWriter.DBObjs.LandBlockInfo;
+
+namespace AcDream.App.Tests.Rendering;
+
+///
+/// #95 MEASUREMENT (2026-06-13): entering the 0x0007 dungeon (Town Network) explodes
+/// WB-DIAG to ~9.1M instances/frame. Suspected cause:
+/// floods the dungeon's portal graph WITHOUT the retail grab_visible_cells stab_list bounding
+/// (decomp:311878). A dungeon cell has seen_outside==0; retail's PVS for it is just the
+/// cell's stab_list () — typically a small bounded
+/// set. If our flood instead visits ~all cells of the landblock, that is the blowup.
+///
+/// This is a DIAGNOSTIC, not a fix: it loads the real 0x0007 interior cells, runs the real
+/// production flood from representative dungeon-cell roots, and PRINTS the ground-truth numbers —
+/// flood visited-cell-set size () vs the
+/// root's stab_list size (), plus how many visited cells
+/// cross landblocks. The single assertion just guarantees the test ran; the VALUE is the output.
+///
+public class Issue95DungeonFloodDiagnosticTests
+{
+ private const uint TownNetwork = 0x00070000u;
+
+ private readonly ITestOutputHelper _out;
+ public Issue95DungeonFloodDiagnosticTests(ITestOutputHelper output) => _out = output;
+
+ // Production-ish projection (mirrors the sibling harnesses): FovY ~1.2, 1280x720,
+ // near 0.1, far 5000. The flood's clip is near-independent, so exactness is not
+ // load-bearing for cell-count measurement.
+ private static Matrix4x4 ViewProjFor(Vector3 eye, Vector3 lookAt)
+ {
+ var view = Matrix4x4.CreateLookAt(eye, lookAt, Vector3.UnitZ);
+ var proj = Matrix4x4.CreatePerspectiveFieldOfView(1.2f, 1280f / 720f, 0.1f, 5000f);
+ return view * proj;
+ }
+
+ [Fact]
+ public void Measure_DungeonFlood_VisibleCellCount()
+ {
+ var datDir = CornerFloodReplayTests.ResolveDatDir();
+ if (datDir is null)
+ {
+ _out.WriteLine("SKIP: dat dir did not resolve (ACDREAM_DAT_DIR unset and "
+ + "%USERPROFILE%\\Documents\\Asheron's Call absent). No numbers measured.");
+ // Diagnostic test: do not hard-fail when dats are absent (matches sibling harnesses).
+ return;
+ }
+ _out.WriteLine($"dat dir resolved: {datDir}");
+
+ using var dats = new DatCollection(datDir, DatAccessType.Read);
+
+ // 1) LandBlockInfo header — NumCells for 0x0007.
+ var lbi = dats.Get(TownNetwork | 0xFFFEu);
+ if (lbi is null)
+ {
+ _out.WriteLine($"SKIP: LandBlockInfo 0x{TownNetwork | 0xFFFEu:X8} not found in the dat "
+ + "(0x0007 may not exist in this client_cell_1.dat).");
+ return;
+ }
+ _out.WriteLine($"=== 0x0007 (Town Network) LandBlockInfo ===");
+ _out.WriteLine($"NumCells (DatLandBlockInfo.NumCells) = {lbi.NumCells}");
+
+ // 2) Load ALL interior cells (sparse ids tolerated — see LoadAllInteriorCells).
+ var loaded = Issue120ReciprocalPingPongTests.LoadAllInteriorCells(dats, TownNetwork);
+ _out.WriteLine($"cells actually loaded = {loaded.Count}");
+ Assert.True(loaded.Count > 0, "no interior cells loaded for 0x0007 — cannot measure");
+
+ Func lookup = id => loaded.TryGetValue(id, out var c) ? c : null;
+
+ // 3) Per-cell stab_list (VisibleCells) distribution across ALL loaded cells.
+ // This is the bounded retail PVS size we expect the flood to roughly match.
+ var stabSizes = loaded.Values.Select(c => c.VisibleCells.Count).ToList();
+ int seenOutsideCount = loaded.Values.Count(c => c.SeenOutside);
+ int interiorCount = loaded.Count - seenOutsideCount;
+ _out.WriteLine("");
+ _out.WriteLine("=== stab_list (LoadedCell.VisibleCells) distribution over ALL loaded cells ===");
+ _out.WriteLine($"cells with SeenOutside==true (entrance/exterior-facing) = {seenOutsideCount}");
+ _out.WriteLine($"cells with SeenOutside==false (interior dungeon) = {interiorCount}");
+ if (stabSizes.Count > 0)
+ _out.WriteLine(FormattableString.Invariant(
+ $"VisibleCells.Count min={stabSizes.Min()} max={stabSizes.Max()} avg={stabSizes.Average():F1} sum={stabSizes.Sum()}"));
+ int emptyStab = stabSizes.Count(s => s == 0);
+ _out.WriteLine($"cells with EMPTY stab_list (no dat PVS) = {emptyStab}");
+
+ // 4) Pick representative DUNGEON roots: the first interior (SeenOutside==false) cells in
+ // ascending id order. If none exist, fall back to 0x00070100 and report that.
+ var interiorRoots = loaded
+ .Where(kv => !kv.Value.SeenOutside)
+ .OrderBy(kv => kv.Key)
+ .Select(kv => kv.Value)
+ .Take(5)
+ .ToList();
+
+ if (interiorRoots.Count == 0)
+ {
+ _out.WriteLine("");
+ _out.WriteLine("NOTE: NO cell has SeenOutside==false (all cells see the exterior). "
+ + "Falling back to root 0x00070100 for the flood measurement.");
+ if (loaded.TryGetValue(TownNetwork | 0x0100u, out var fallback))
+ interiorRoots.Add(fallback);
+ else
+ {
+ _out.WriteLine("WARN: 0x00070100 not loaded either; using the lowest-id loaded cell.");
+ interiorRoots.Add(loaded.OrderBy(kv => kv.Key).First().Value);
+ }
+ }
+
+ _out.WriteLine("");
+ _out.WriteLine("=== PER-ROOT FLOOD MEASUREMENT (PortalVisibilityBuilder.Build) ===");
+ _out.WriteLine("property read for the visited-cell set: PortalVisibilityFrame.OrderedVisibleCells");
+ _out.WriteLine("root | seenOut | stab(VisibleCells) | flood(OrderedVisibleCells) | crossLB | dir");
+
+ var floodSizes = new List();
+ foreach (var root in interiorRoots)
+ {
+ // Eye at the root cell's world origin, looking toward its first portal (or +X if none),
+ // so the flood actually fires through an opening. Sweep all 6 axis directions and KEEP
+ // the maximum visited-set — the blowup is a worst-case-over-orientation quantity.
+ var eye = root.WorldPosition;
+ int bestFlood = -1;
+ string bestDir = "?";
+ int bestCrossLb = -1;
+ List? bestVisited = null;
+
+ // Direction candidates: toward each portal's polygon centroid (the natural look-through),
+ // plus the 6 cardinal axes as a fallback sweep.
+ var lookTargets = new List<(Vector3 target, string label)>();
+ for (int pi = 0; pi < root.Portals.Count && pi < root.PortalPolygons.Count; pi++)
+ {
+ var poly = root.PortalPolygons[pi];
+ if (poly is { Length: >= 1 })
+ {
+ var cl = Vector3.Zero;
+ foreach (var v in poly) cl += v;
+ cl /= poly.Length;
+ lookTargets.Add((Vector3.Transform(cl, root.WorldTransform),
+ $"portal{pi}->0x{root.Portals[pi].OtherCellId:X4}"));
+ }
+ }
+ foreach (var (d, lbl) in new (Vector3, string)[]
+ {
+ (Vector3.UnitX, "+X"), (-Vector3.UnitX, "-X"),
+ (Vector3.UnitY, "+Y"), (-Vector3.UnitY, "-Y"),
+ (Vector3.UnitZ, "+Z"), (-Vector3.UnitZ, "-Z"),
+ })
+ lookTargets.Add((eye + d * 5f, lbl));
+
+ foreach (var (target, label) in lookTargets)
+ {
+ if (Vector3.DistanceSquared(target, eye) < 1e-6f) continue;
+ var frame = PortalVisibilityBuilder.Build(root, eye, lookup, ViewProjFor(eye, target));
+ int floodN = frame.OrderedVisibleCells.Count;
+ if (floodN > bestFlood)
+ {
+ bestFlood = floodN;
+ bestDir = label;
+ bestVisited = frame.OrderedVisibleCells;
+ bestCrossLb = frame.OrderedVisibleCells.Count(id => (id & 0xFFFF0000u) != TownNetwork);
+ }
+ }
+
+ floodSizes.Add(bestFlood);
+ _out.WriteLine(FormattableString.Invariant(
+ $"0x{root.CellId:X8} | {(root.SeenOutside ? "Y" : "N"),5} | {root.VisibleCells.Count,18} | {bestFlood,26} | {bestCrossLb,7} | {bestDir}"));
+
+ // For the FIRST root, also print the actual visited set + stab set for eyeballing.
+ if (ReferenceEquals(root, interiorRoots[0]) && bestVisited is not null)
+ {
+ _out.WriteLine(" first-root visited (OrderedVisibleCells, low ids): "
+ + string.Join(" ", bestVisited.Select(id => $"{id & 0xFFFFu:X4}")));
+ _out.WriteLine(" first-root stab_list (VisibleCells, low ids): "
+ + string.Join(" ", root.VisibleCells.Select(id => $"{id & 0xFFFFu:X4}")));
+ }
+ }
+
+ // 5) Aggregate flood-size stats across the sampled roots — the headline numbers.
+ _out.WriteLine("");
+ _out.WriteLine("=== AGGREGATE over sampled roots ===");
+ if (floodSizes.Count > 0)
+ _out.WriteLine(FormattableString.Invariant(
+ $"flood visited-set size (OrderedVisibleCells): min={floodSizes.Min()} max={floodSizes.Max()} avg={floodSizes.Average():F1} (NumCells={lbi.NumCells}, loaded={loaded.Count})"));
+ var sampledStab = interiorRoots.Select(r => r.VisibleCells.Count).ToList();
+ if (sampledStab.Count > 0)
+ _out.WriteLine(FormattableString.Invariant(
+ $"sampled roots' stab_list size (VisibleCells): min={sampledStab.Min()} max={sampledStab.Max()} avg={sampledStab.Average():F1}"));
+ _out.WriteLine("");
+ _out.WriteLine("INTERPRETATION: if flood max ~= loaded.Count (visits ~all cells) while stab "
+ + "is small, that is the #95 blowup — the flood is unbounded by the retail stab_list PVS.");
+ }
+}