diff --git a/docs/release-gate.md b/docs/release-gate.md
index 35c3cbcd..473a3e5d 100644
--- a/docs/release-gate.md
+++ b/docs/release-gate.md
@@ -12,9 +12,9 @@ The command verifies that `AcDream.slnx` contains every `.csproj` under `src/`,
then discovers and runs every hermetic test in every default test assembly once
in a fresh Release process. It does not retry failures. Tests carrying an
explicit non-hermetic `Lane` trait (`InstalledDat`, `PreparedPackage`, `Live`,
-or `Manual`), `Purpose=Diagnostic`, or `Status=KnownFailure` are excluded from
-the hermetic total and run through their owned lane instead. The graph currently
-contains 44 projects,
+`Manual`, `Windows`, `Linux`, or `SystemFont`), `Purpose=Diagnostic`, or
+`Status=KnownFailure` are excluded from the hermetic total and run through
+their owned lane instead. The graph currently contains 44 projects,
including all 13 maintained .NET tools; data-dependent tools are built but are
not executed as tests.
@@ -79,8 +79,18 @@ Installed-DAT tests require an explicit opt-in and a retail DAT directory:
```powershell
$env:ACDREAM_RUN_INSTALLED_DAT_TESTS = '1'
$env:ACDREAM_DAT_DIR = 'C:\path\to\Asherons Call'
-dotnet test tests/AcDream.App.Tests/AcDream.App.Tests.csproj -c Release `
- --filter 'Lane=InstalledDat&Status!=KnownFailure&Purpose!=Diagnostic'
+pwsh ./tools/run-release-gate.ps1 -SkipRestore -SkipBuild `
+ -TestFilter 'Lane=InstalledDat&Status!=KnownFailure&Purpose!=Diagnostic'
+```
+
+The prepared-package lane additionally requires a validated `acdream.pak`
+beside the DATs or at `ACDREAM_PAK_PATH`:
+
+```powershell
+$env:ACDREAM_DAT_DIR = 'C:\path\to\Asherons Call'
+$env:ACDREAM_PAK_PATH = 'C:\path\to\acdream.pak'
+pwsh ./tools/run-release-gate.ps1 -SkipRestore -SkipBuild `
+ -TestFilter 'Lane=PreparedPackage&Status!=KnownFailure&Purpose!=Diagnostic'
```
Regenerate all committed UI fixtures through the one comprehensive manual
@@ -109,6 +119,14 @@ dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Release `
--filter 'Purpose=Diagnostic'
```
+Operating-system contracts are likewise explicit. Run `Lane=Windows` on a
+Windows host and `Lane=Linux` on a native Linux host; a lane is not portable
+evidence when executed on the other operating system.
+
+`Lane=SystemFont` exercises the BitmapFont path against a host-provided TTF.
+It is separate because the supported runtime can legitimately have none of the
+well-known development fonts installed.
+
## Updating dependencies
Do not edit lock files by hand. To make an intentional dependency change:
diff --git a/docs/reviews/2026-08-18-r3-test-truth-ledger.md b/docs/reviews/2026-08-18-r3-test-truth-ledger.md
index 107704ee..09677293 100644
--- a/docs/reviews/2026-08-18-r3-test-truth-ledger.md
+++ b/docs/reviews/2026-08-18-r3-test-truth-ledger.md
@@ -127,7 +127,7 @@ identifiable in the lane report.
| T-004 warning mismatches | resolved in R2 | Clean rebuild is zero-warning with repository-wide warnings-as-errors. |
| T-005 unreachable panel stack | requires production reachability proof | Do not delete 52 meaningful tests until the dead presentation surface and any supported plugin compatibility promise are verified together. |
| T-006 misleading installed-DAT reason | resolved in batch B | Shared opt-in is now `ACDREAM_RUN_INSTALLED_DAT_TESTS=1` (legacy switch retained), the reason names the lane, and all nine owners carry `Lane=InstalledDat`. |
-| T-007 271 silent passing gates | active; current candidate set generated | Current syntax has 282 prerequisite-return candidates across seven projects. Inspect/classify from the generated manifest; the count changed with source growth and includes platform gates, so do not mechanically rewrite all 282. |
+| T-007 271 silent passing gates | lane classification complete in batch D; body cleanup active | Of 282 current candidates, 280 are true prerequisite gates and now have an explicit lane. The two unlaned methods are reviewed false positives that assert the current Windows/Linux branch before returning. Empty-return removal remains, lane by lane. |
| T-008 incapable-of-failing diagnostics | batch A plus diagnostic lane work | Delete the literal wiring smoke test; repair the GPU contract tautology; later re-home output-only apparatus. |
| T-009 wall-clock double-click tests | open | Introduce a behavior-preserving injectable monotonic clock and deterministic fake time. |
| T-010 two useless cases | high-confidence cleanup batch A | Delete `SmokeTest.TestProject_IsWired` and `ChaseCameraTests.ImplementsICamera`; compilation already proves both claims. |
@@ -137,7 +137,7 @@ identifiable in the lane report.
| T-014 seven load-sensitive tests | active; first mechanism reproduced | `PortalProjectionTests.ClipToRegion_FrameOwnedStore_ReusesExactResultArray` reported 6,904 B only while three App test hosts ran concurrently, then passed in an isolated run. Preserve both observations and remove ambient process-allocation sensitivity rather than loosening the zero-allocation oracle. |
| T-015 four non-prerequisite skips | resolved in batches A/B | PVS scaffold deleted with rationale preserved; redundant chat/radar generators deleted in favor of the comprehensive Manual lane; tower oracle is `Status=KnownFailure`. |
| T-016 historical test taxonomy | open | Rename/re-home only after each test's durable owner and oracle are established. |
-| T-017 Avalonia ownership | resolved in R2 | All seven editor variants now execute in one owned application session; 11 focused passes plus the complete gate. |
+| T-017 Avalonia ownership | reopened and closed in batch D | The full gate exposed the same compositor ownership class between six newer `MainWindowViewTests` facts. Their six named assertion phases now run in one owned Avalonia application session; 25 fresh-process stress iterations and the complete gate pass. |
| T-018 stderr observer race | resolved in R2 | Live reader shares writes/deletes; 25 focused repetitions plus the complete gate. |
## Preserved rationale for removals in batch A
@@ -251,3 +251,62 @@ An attempted parallel App/Core build collided on the shared
`AcDream.Plugin.Abstractions` intermediate DLL. The repository gate serializes
projects, so the authoritative verification is the two isolated clean builds
above; no code or assertion was changed in response to that tooling collision.
+
+## Batch D prerequisite lanes and Avalonia ownership
+
+The reviewed prerequisite map classifies every true candidate without deleting
+its existing guard:
+
+| Lane | Attributed methods | Prerequisite |
+|---|---:|---|
+| `InstalledDat` | 336 | Installed retail DAT directory; includes the 73 custom installed-DAT facts and whole DAT-backed investigation classes. |
+| `PreparedPackage` | 2 | Installed DATs plus validated `acdream.pak`. |
+| `Live` | 3 | Explicit live handshake opt-in and reachable service. |
+| `Manual` | 1 | Explicit fixture-regeneration opt-in. |
+| `Windows` | 7 | Windows-only filesystem/process/timer behavior. |
+| `Linux` | 10 | Linux permission/signal/monotonic-clock behavior. |
+| `SystemFont` | 2 | A host system TTF available to the BitmapFont path. |
+
+Class-level traits legitimately cover some additional methods that share the
+same fixture owner, so the 336 installed-DAT method count is larger than the
+280 syntax candidates. The only candidate methods without a lane are
+`GraphicalHostPlatformServicesTests.CurrentPlatformOwnsPathsPacingAndNativeClosure`
+and
+`LinuxMonotonicFramePacingWaiterTests.PlatformFactorySelectsCurrentOperatingSystem`.
+Both are hermetic cross-platform branch tests: on Windows or Linux they assert
+the matching branch and return only after the assertion. They are not silent
+prerequisite passes.
+
+The 11 conditional `SkipException.ForSkip` source sites are also reconciled.
+They serve 12 test methods: installed-DAT asset contracts, one prepared-package
+contract, and two system-font contracts. xUnit v2 reports that exception shape
+as a failure rather than a dynamic skip, but the owning lanes now keep them out
+of the hermetic total. A later body-cleanup batch will replace the misleading
+skip wording/exception with explicit prerequisite failure or discovery-time
+lane behavior.
+
+The first complete Batch D gate correctly failed in Launcher cleanup after
+14,396 passes: the six `MainWindowViewTests` Avalonia facts could start and
+destroy isolated thread-affine compositors on different xUnit workers. The
+assertion bodies were preserved as six named private phases under one
+`CompiledMarkupAndEveryModalFocusPathRunInOneOwnedAvaloniaSession` fact. The
+focused two-case class then passed in 25 consecutive fresh processes (50/50
+results), and the same full-gate context passed.
+
+Batch D verification:
+
+- complete 44-project Release build: 0 warnings, 0 errors;
+- final syntax manifest: 11,450 attributed methods, 51 diagnostics, one known
+ failure, 282 prerequisite-return candidates, and only the two reviewed
+ cross-platform false positives unlaned;
+- complete hermetic Release gate: 14,392 passed / 0 skipped / 0 failed across
+ all 12 test assemblies in 131.518 seconds; and
+- Launcher view stress: 25 fresh processes, 2/2 cases per process, no cleanup
+ or ownership failures.
+
+The 350-pass reduction from the clean R2 headline is exactly explained: batch A
+netted minus one case; batch B removed six non-hermetic passes; batch C removed
+68 newly classified diagnostic cases; batch D removed 270 prerequisite-lane
+passes; and consolidating the six Avalonia sessions into one removed five case
+IDs without removing any assertion phase. All 77 former default skips are also
+accounted for by the PVS deletion and batch-B lane/deletion decisions.
diff --git a/tests/AcDream.App.Tests/Credentials/AppCredentialResolverTests.cs b/tests/AcDream.App.Tests/Credentials/AppCredentialResolverTests.cs
index 49eb9820..144a93c3 100644
--- a/tests/AcDream.App.Tests/Credentials/AppCredentialResolverTests.cs
+++ b/tests/AcDream.App.Tests/Credentials/AppCredentialResolverTests.cs
@@ -131,6 +131,7 @@ public sealed class AppCredentialResolverTests
}
[Fact]
+ [Trait("Lane", "Linux")]
public void LinuxRejectsGroupOrOtherCredentialPermissions()
{
if (!OperatingSystem.IsLinux())
diff --git a/tests/AcDream.App.Tests/Rendering/ChargenPreviewEntityBuilderTests.cs b/tests/AcDream.App.Tests/Rendering/ChargenPreviewEntityBuilderTests.cs
index 68fb5fcb..4cd35d74 100644
--- a/tests/AcDream.App.Tests/Rendering/ChargenPreviewEntityBuilderTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/ChargenPreviewEntityBuilderTests.cs
@@ -20,6 +20,7 @@ namespace AcDream.App.Tests.Rendering;
/// is resolving Setup/GfxObj/Surface/Animation dat data that
/// receives pre-resolved).
///
+[Trait("Lane", "InstalledDat")]
public sealed class ChargenPreviewEntityBuilderTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/CornerFloodReplayTests.cs b/tests/AcDream.App.Tests/Rendering/CornerFloodReplayTests.cs
index 74da2f81..0abff4e9 100644
--- a/tests/AcDream.App.Tests/Rendering/CornerFloodReplayTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/CornerFloodReplayTests.cs
@@ -198,6 +198,7 @@ public class CornerFloodReplayTests
/// exact gate that flips.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Diagnostic_TraceGoodVsGlitchStep()
{
var datDir = ResolveDatDir();
@@ -266,6 +267,7 @@ public class CornerFloodReplayTests
/// transition background strobe). Guards the ApplyReciprocalClip pipeline.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void CornerSweep_FloodIsCompleteAndMonotone()
{
var datDir = ResolveDatDir();
@@ -363,6 +365,7 @@ public class CornerFloodReplayTests
/// the tripwire count stays 0.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void PortalPlaneCrossings_InPlacePropagationConverges()
{
var datDir = ResolveDatDir();
@@ -433,6 +436,7 @@ public class CornerFloodReplayTests
/// stays 0 across every Build.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InCellDirectionSweep_InPlacePropagationConverges()
{
var datDir = ResolveDatDir();
@@ -495,6 +499,7 @@ public class CornerFloodReplayTests
/// the collapsing intersection.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Diagnostic_Hop2Microscope()
{
var datDir = ResolveDatDir();
@@ -625,6 +630,7 @@ public class CornerFloodReplayTests
/// 0171/0173 — the screen area where the player stands then shows background.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Diagnostic_CornerPress_FloodAcrossDoorwayPlane()
{
var datDir = ResolveDatDir();
diff --git a/tests/AcDream.App.Tests/Rendering/FramePacingControllerTests.cs b/tests/AcDream.App.Tests/Rendering/FramePacingControllerTests.cs
index fded1c1b..7d9eaf5b 100644
--- a/tests/AcDream.App.Tests/Rendering/FramePacingControllerTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/FramePacingControllerTests.cs
@@ -119,6 +119,7 @@ public sealed class FramePacingControllerTests
}
[Fact]
+ [Trait("Lane", "Windows")]
public void Windows_high_resolution_timer_arms_and_disposes_its_handle()
{
if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
diff --git a/tests/AcDream.App.Tests/Rendering/HouseExitWalkReplayTests.cs b/tests/AcDream.App.Tests/Rendering/HouseExitWalkReplayTests.cs
index ab1f1604..e16970a3 100644
--- a/tests/AcDream.App.Tests/Rendering/HouseExitWalkReplayTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/HouseExitWalkReplayTests.cs
@@ -49,6 +49,7 @@ namespace AcDream.App.Tests.Rendering;
/// OutsideView ⇒ outdoor dynamics trivially cone-pass).
///
[Collection(CameraDiagnosticsCollection.Name)]
+[Trait("Lane", "InstalledDat")]
public class HouseExitWalkReplayTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue113DrawingBspFilterTests.cs b/tests/AcDream.App.Tests/Rendering/Issue113DrawingBspFilterTests.cs
index a1c95cff..5cabba02 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue113DrawingBspFilterTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue113DrawingBspFilterTests.cs
@@ -19,6 +19,7 @@ namespace AcDream.App.Tests.Rendering;
/// iterated the dictionary and drew the "phantom staircase". These pins hold
/// ObjectMeshManager.CollectDrawingBspPolygonIds to the dat facts.
///
+[Trait("Lane", "InstalledDat")]
public class Issue113DrawingBspFilterTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue113MeetingHallFloodTests.cs b/tests/AcDream.App.Tests/Rendering/Issue113MeetingHallFloodTests.cs
index 14b0e6c3..7b379aba 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue113MeetingHallFloodTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue113MeetingHallFloodTests.cs
@@ -29,6 +29,7 @@ namespace AcDream.App.Tests.Rendering;
/// production assembler from the user's click-time viewpoint and pins which
/// hall cells draw and with what clip.
///
+[Trait("Lane", "InstalledDat")]
public class Issue113MeetingHallFloodTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue120ReciprocalPingPongTests.cs b/tests/AcDream.App.Tests/Rendering/Issue120ReciprocalPingPongTests.cs
index c1b86334..403f08a5 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue120ReciprocalPingPongTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue120ReciprocalPingPongTests.cs
@@ -34,6 +34,7 @@ namespace AcDream.App.Tests.Rendering;
/// contained polygons, which makes union growth strictly area-increasing and
/// the flood convergent regardless of clip-numerics drift.
///
+[Trait("Lane", "InstalledDat")]
public class Issue120ReciprocalPingPongTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue124LookInSeedRegionTests.cs b/tests/AcDream.App.Tests/Rendering/Issue124LookInSeedRegionTests.cs
index 75a964b1..775a8b9f 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue124LookInSeedRegionTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue124LookInSeedRegionTests.cs
@@ -18,6 +18,7 @@ namespace AcDream.App.Tests.Rendering;
/// seedRegion parameter — the port of that installed-view clip — against the
/// real Holtburg corner-building door.
///
+[Trait("Lane", "InstalledDat")]
public class Issue124LookInSeedRegionTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue130DoorwayStripTests.cs b/tests/AcDream.App.Tests/Rendering/Issue130DoorwayStripTests.cs
index 2f779822..4c643f8b 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue130DoorwayStripTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue130DoorwayStripTests.cs
@@ -38,6 +38,7 @@ namespace AcDream.App.Tests.Rendering;
/// cut). Fixed by the conservative NdcScissorRect bound; the assertions below
/// pin both properties.
///
+[Trait("Lane", "InstalledDat")]
public class Issue130DoorwayStripTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs b/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs
index 808c2ab1..7f6b7ccb 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.App.Tests.Rendering;
/// translucent swirl; lamp posts / creatures / signs identify by part shape.
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public class Issue131SetupProbeTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue176177FacilityHubFloodReplayTests.cs b/tests/AcDream.App.Tests/Rendering/Issue176177FacilityHubFloodReplayTests.cs
index e95dc97b..6307eecd 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue176177FacilityHubFloodReplayTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue176177FacilityHubFloodReplayTests.cs
@@ -33,6 +33,7 @@ namespace AcDream.App.Tests.Rendering;
/// D. #176 walk — eye tracks down the corridor across two seams, gaze
/// locked +X: per-step admitted-set diffs (drop-for-one-step churn).
///
+[Trait("Lane", "InstalledDat")]
public class Issue176177FacilityHubFloodReplayTests
{
private const uint FacilityHub = 0x8A020000u;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue177StairDescentCameraFloodTests.cs b/tests/AcDream.App.Tests/Rendering/Issue177StairDescentCameraFloodTests.cs
index f10f0bc7..357f5a96 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue177StairDescentCameraFloodTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue177StairDescentCameraFloodTests.cs
@@ -32,6 +32,7 @@ namespace AcDream.App.Tests.Rendering;
/// admitted, the flood is exonerated and the artifact lives downstream.
///
[Collection(CameraDiagnosticsCollection.Name)]
+[Trait("Lane", "InstalledDat")]
public class Issue177StairDescentCameraFloodTests
{
private const uint FacilityHub = 0x8A020000u;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs b/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs
index c1da7914..d6e4efec 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue181VisFlapReplayTests.cs
@@ -22,6 +22,7 @@ namespace AcDream.App.Tests.Rendering;
/// axis; ANY admitted-set difference at sub-mm perturbation is the #181
/// instability, and the symmetric difference names the flapping cell.
///
+[Trait("Lane", "InstalledDat")]
public class Issue181VisFlapReplayTests
{
private const uint FacilityHub = 0x8A020000u;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue181WallPressEquilibriumTests.cs b/tests/AcDream.App.Tests/Rendering/Issue181WallPressEquilibriumTests.cs
index 3930723d..5f5fee5b 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue181WallPressEquilibriumTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue181WallPressEquilibriumTests.cs
@@ -33,6 +33,7 @@ namespace AcDream.App.Tests.Rendering;
///
[Collection(CameraDiagnosticsCollection.Name)]
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public class Issue181WallPressEquilibriumTests
{
private const uint FacilityHubLandblock = 0x8A020000u;
diff --git a/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs b/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs
index 5e5f1228..a1bce2f9 100644
--- a/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/Issue95DungeonFloodDiagnosticTests.cs
@@ -25,6 +25,7 @@ namespace AcDream.App.Tests.Rendering;
/// 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.
///
+[Trait("Lane", "InstalledDat")]
public class Issue95DungeonFloodDiagnosticTests
{
private const uint TownNetwork = 0x00070000u;
diff --git a/tests/AcDream.App.Tests/Rendering/LinuxMonotonicFramePacingWaiterTests.cs b/tests/AcDream.App.Tests/Rendering/LinuxMonotonicFramePacingWaiterTests.cs
index 53876839..e62336fd 100644
--- a/tests/AcDream.App.Tests/Rendering/LinuxMonotonicFramePacingWaiterTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/LinuxMonotonicFramePacingWaiterTests.cs
@@ -48,6 +48,7 @@ public sealed class LinuxMonotonicFramePacingWaiterTests
}
[Fact]
+ [Trait("Lane", "Linux")]
public void LinuxWaitBlocksUntilRequestedMonotonicDeadline()
{
if (!OperatingSystem.IsLinux())
@@ -70,6 +71,7 @@ public sealed class LinuxMonotonicFramePacingWaiterTests
}
[Fact]
+ [Trait("Lane", "Linux")]
public void LinuxWaiterRejectsUseAfterDisposal()
{
if (!OperatingSystem.IsLinux())
diff --git a/tests/AcDream.App.Tests/Rendering/PortalTunnelAssetTests.cs b/tests/AcDream.App.Tests/Rendering/PortalTunnelAssetTests.cs
index 1a825b82..a913d15d 100644
--- a/tests/AcDream.App.Tests/Rendering/PortalTunnelAssetTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/PortalTunnelAssetTests.cs
@@ -52,6 +52,7 @@ public sealed class PortalTunnelAssetTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledDat_ResolvesRetailPortalSetupAndAnimation()
{
string? datDir = ResolveDatDir();
diff --git a/tests/AcDream.App.Tests/Rendering/RetailParticleGeometryClassifierTests.cs b/tests/AcDream.App.Tests/Rendering/RetailParticleGeometryClassifierTests.cs
index f1a2f6e9..0a1f7421 100644
--- a/tests/AcDream.App.Tests/Rendering/RetailParticleGeometryClassifierTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/RetailParticleGeometryClassifierTests.cs
@@ -206,6 +206,7 @@ public sealed class RetailParticleGeometryClassifierTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledArmorSelfShieldPieces_areModeOneMeshesWithAuthoredApexFaces()
{
string? datDir = ResolveDatDir();
@@ -264,6 +265,7 @@ public sealed class RetailParticleGeometryClassifierTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledHumanEffectTable_MapsPortalVisibilityScripts()
{
string? datDir = ResolveDatDir();
@@ -278,6 +280,7 @@ public sealed class RetailParticleGeometryClassifierTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledAerlintheSwarmEmitter_UsesItsHardwareGfxDegradeDistance()
{
string? datDir = ResolveDatDir();
diff --git a/tests/AcDream.App.Tests/Rendering/RetailSelectionAssetTests.cs b/tests/AcDream.App.Tests/Rendering/RetailSelectionAssetTests.cs
index 8a6f3c61..8be5c77e 100644
--- a/tests/AcDream.App.Tests/Rendering/RetailSelectionAssetTests.cs
+++ b/tests/AcDream.App.Tests/Rendering/RetailSelectionAssetTests.cs
@@ -16,6 +16,7 @@ namespace AcDream.App.Tests.Rendering;
public sealed class RetailSelectionAssetTests
{
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledDat_ResolvesAllTwelveVividTargetImages()
{
string datDir = ResolveDatDir();
@@ -58,6 +59,7 @@ public sealed class RetailSelectionAssetTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void DoorSelectionGeometry_UsesDrawingBspRootSphereAndDatPolygonOrder()
{
const uint doorGfxObjId = 0x010044B5u;
diff --git a/tests/AcDream.App.Tests/Streaming/LandblockBuildFactoryTests.cs b/tests/AcDream.App.Tests/Streaming/LandblockBuildFactoryTests.cs
index 0fc1c0c0..64cd75d1 100644
--- a/tests/AcDream.App.Tests/Streaming/LandblockBuildFactoryTests.cs
+++ b/tests/AcDream.App.Tests/Streaming/LandblockBuildFactoryTests.cs
@@ -318,6 +318,7 @@ public sealed class LandblockBuildFactoryTests
}
[Fact]
+ [Trait("Lane", "PreparedPackage")]
public void InstalledDatNearBuild_IsDeterministicAndClosesEntityPhysicsPayload()
{
string? datDirectory = ResolveDatDirectory();
diff --git a/tests/AcDream.App.Tests/UI/IconComposerTests.cs b/tests/AcDream.App.Tests/UI/IconComposerTests.cs
index ba35d60d..619b91eb 100644
--- a/tests/AcDream.App.Tests/UI/IconComposerTests.cs
+++ b/tests/AcDream.App.Tests/UI/IconComposerTests.cs
@@ -75,6 +75,7 @@ public class IconComposerTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void ResolveUnderlayDid_goldenValues_matchDat()
{
var datDir = ResolveDatDir();
@@ -103,6 +104,7 @@ public class IconComposerTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void ResolveEffectDid_goldenValues_matchDat()
{
var datDir = ResolveDatDir();
@@ -128,6 +130,7 @@ public class IconComposerTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void TryGetEffectTile_noEffectBlack_magicalTextured()
{
var datDir = ResolveDatDir();
diff --git a/tests/AcDream.App.Tests/UI/Layout/CharacterLayoutImportProbe.cs b/tests/AcDream.App.Tests/UI/Layout/CharacterLayoutImportProbe.cs
index 73d3d0c7..352098b0 100644
--- a/tests/AcDream.App.Tests/UI/Layout/CharacterLayoutImportProbe.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/CharacterLayoutImportProbe.cs
@@ -11,6 +11,7 @@ using Xunit;
namespace AcDream.App.Tests.UI.Layout;
+[Trait("Lane", "InstalledDat")]
public sealed class CharacterLayoutImportProbe
{
private const uint CharacterLayout = 0x2100002Eu;
diff --git a/tests/AcDream.App.Tests/UI/Layout/ChatIndicatorButtonLiveMountProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/ChatIndicatorButtonLiveMountProbeTests.cs
index 57ef524b..1fbc6e1f 100644
--- a/tests/AcDream.App.Tests/UI/Layout/ChatIndicatorButtonLiveMountProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/ChatIndicatorButtonLiveMountProbeTests.cs
@@ -54,6 +54,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// see its own class doc) are unaffected.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class ChatIndicatorButtonLiveMountProbeTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/Layout/ChatOptionsDatDefaultsTests.cs b/tests/AcDream.App.Tests/UI/Layout/ChatOptionsDatDefaultsTests.cs
index a3638377..e28b9693 100644
--- a/tests/AcDream.App.Tests/UI/Layout/ChatOptionsDatDefaultsTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/ChatOptionsDatDefaultsTests.cs
@@ -16,6 +16,7 @@ namespace AcDream.App.Tests.UI.Layout;
public sealed class ChatOptionsDatDefaultsTests
{
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledDat_ResolvesTheByteVerifiedSliderDefaults()
{
string datDir = ResolveDatDir();
diff --git a/tests/AcDream.App.Tests/UI/Layout/FaPanelSlotProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/FaPanelSlotProbeTests.cs
index afee951e..5a8e0520 100644
--- a/tests/AcDream.App.Tests/UI/Layout/FaPanelSlotProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/FaPanelSlotProbeTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// and 0x10000263 (swear-allegiance button). Env-gated like the other probes.
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public sealed class FaPanelSlotProbeTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/Layout/InventoryFrameImportProbe.cs b/tests/AcDream.App.Tests/UI/Layout/InventoryFrameImportProbe.cs
index 32e074fe..3925141e 100644
--- a/tests/AcDream.App.Tests/UI/Layout/InventoryFrameImportProbe.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/InventoryFrameImportProbe.cs
@@ -18,6 +18,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// backdrop (ZLevel 100 → ≈ −1,000,000), and the backdrop washed out the panels' captions,
/// burden meter, and item cells. Skips when the live dat directory is absent (CI).
///
+[Trait("Lane", "InstalledDat")]
public class InventoryFrameImportProbe
{
private const uint Frame = 0x21000023u;
diff --git a/tests/AcDream.App.Tests/UI/Layout/ItemAppraisalTextFormatterTests.cs b/tests/AcDream.App.Tests/UI/Layout/ItemAppraisalTextFormatterTests.cs
index 24e4fe75..e4d66bd5 100644
--- a/tests/AcDream.App.Tests/UI/Layout/ItemAppraisalTextFormatterTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/ItemAppraisalTextFormatterTests.cs
@@ -749,6 +749,7 @@ public sealed class ItemAppraisalTextFormatterTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void EndOfRetailDatNameResolver_LoadsMaterialAndCreatureNames()
{
string? datDirectory = ResolveDatDirectory();
diff --git a/tests/AcDream.App.Tests/UI/Layout/ItemListCellTemplateTests.cs b/tests/AcDream.App.Tests/UI/Layout/ItemListCellTemplateTests.cs
index 635364b9..f4facea0 100644
--- a/tests/AcDream.App.Tests/UI/Layout/ItemListCellTemplateTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/ItemListCellTemplateTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// square 0x060074CF. Also PRINTS the resolved ids — the "pin the exact asset" record.
/// Skips when the live dat directory is absent (CI).
///
+[Trait("Lane", "InstalledDat")]
public class ItemListCellTemplateTests
{
private const uint Generic = 0x060074CFu; // generic toolbar-shortcut empty square (the bug)
diff --git a/tests/AcDream.App.Tests/UI/Layout/KeyboardConfigLiveMountProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/KeyboardConfigLiveMountProbeTests.cs
index c5ec5d80..2ba9e7da 100644
--- a/tests/AcDream.App.Tests/UI/Layout/KeyboardConfigLiveMountProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/KeyboardConfigLiveMountProbeTests.cs
@@ -16,6 +16,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// rect + caption evidence for each observation. Env-gated like the other
/// live probes so CI/dat-less runs skip it.
///
+[Trait("Lane", "InstalledDat")]
public sealed class KeyboardConfigLiveMountProbeTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/Layout/MapHousePanelSlotProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/MapHousePanelSlotProbeTests.cs
index e9696d0f..18b02e1e 100644
--- a/tests/AcDream.App.Tests/UI/Layout/MapHousePanelSlotProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/MapHousePanelSlotProbeTests.cs
@@ -26,6 +26,7 @@ namespace AcDream.App.Tests.UI.Layout;
///
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public sealed class MapHousePanelSlotProbeTests
{
private const uint HostLayoutId = 0x2100006Eu;
diff --git a/tests/AcDream.App.Tests/UI/Layout/OptionsPanelLiveMountProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/OptionsPanelLiveMountProbeTests.cs
index 540ab27d..7fca9a45 100644
--- a/tests/AcDream.App.Tests/UI/Layout/OptionsPanelLiveMountProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/OptionsPanelLiveMountProbeTests.cs
@@ -16,6 +16,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// page controller actually resolves. Env-gated like the fixture
/// generator so CI/dat-less runs skip it.
///
+[Trait("Lane", "InstalledDat")]
public sealed class OptionsPanelLiveMountProbeTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/Layout/PaperdollClickMapTests.cs b/tests/AcDream.App.Tests/UI/Layout/PaperdollClickMapTests.cs
index 44fc107c..e9c85a2c 100644
--- a/tests/AcDream.App.Tests/UI/Layout/PaperdollClickMapTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/PaperdollClickMapTests.cs
@@ -45,6 +45,7 @@ public sealed class PaperdollClickMapTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void LiveDat_resolvesRetailClickMapAndAllNineBodyRegions()
{
string datDir = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
diff --git a/tests/AcDream.App.Tests/UI/Layout/PaperdollSlotBackgroundTests.cs b/tests/AcDream.App.Tests/UI/Layout/PaperdollSlotBackgroundTests.cs
index d641952b..90999c0c 100644
--- a/tests/AcDream.App.Tests/UI/Layout/PaperdollSlotBackgroundTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/PaperdollSlotBackgroundTests.cs
@@ -47,6 +47,7 @@ public class PaperdollSlotBackgroundTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Live_dat_resolves_all_pinned_retail_backgrounds()
{
string datDir = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
diff --git a/tests/AcDream.App.Tests/UI/Layout/PowerbarLayoutProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/PowerbarLayoutProbeTests.cs
index 7a79ea84..22ede98e 100644
--- a/tests/AcDream.App.Tests/UI/Layout/PowerbarLayoutProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/PowerbarLayoutProbeTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// INSTALLED DAT, so the "Height"/"Power"/"Accuracy" fix binds exactly what
/// retail authors instead of guessing.
///
+[Trait("Lane", "InstalledDat")]
public sealed class PowerbarLayoutProbeTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/Layout/SocialPanelLiveMountProbeTests.cs b/tests/AcDream.App.Tests/UI/Layout/SocialPanelLiveMountProbeTests.cs
index 5e4eeb8f..2fe07b29 100644
--- a/tests/AcDream.App.Tests/UI/Layout/SocialPanelLiveMountProbeTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/SocialPanelLiveMountProbeTests.cs
@@ -18,6 +18,7 @@ namespace AcDream.App.Tests.UI.Layout;
/// its button→page pairing + default entry can be recorded — coordinator
/// addendum, docs/research/2026-08-11-fa-panel-structure.md §10.
///
+[Trait("Lane", "InstalledDat")]
public sealed class SocialPanelLiveMountProbeTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/Layout/SpellbookRowStyleTests.cs b/tests/AcDream.App.Tests/UI/Layout/SpellbookRowStyleTests.cs
index 5adbab21..60cf82e7 100644
--- a/tests/AcDream.App.Tests/UI/Layout/SpellbookRowStyleTests.cs
+++ b/tests/AcDream.App.Tests/UI/Layout/SpellbookRowStyleTests.cs
@@ -4,6 +4,7 @@ using DatReaderWriter.Options;
namespace AcDream.App.Tests.UI.Layout;
+[Trait("Lane", "InstalledDat")]
public sealed class SpellbookRowStyleTests
{
[Fact]
diff --git a/tests/AcDream.App.Tests/UI/RetailCursorCatalogTests.cs b/tests/AcDream.App.Tests/UI/RetailCursorCatalogTests.cs
index 8a34765b..ea6aad85 100644
--- a/tests/AcDream.App.Tests/UI/RetailCursorCatalogTests.cs
+++ b/tests/AcDream.App.Tests/UI/RetailCursorCatalogTests.cs
@@ -24,6 +24,7 @@ public sealed class RetailCursorCatalogTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void WindowControlCursorSpecs_resolveGoldenDatSurfaces()
{
string? datDir = ResolveDatDir();
@@ -82,6 +83,7 @@ public sealed class RetailCursorCatalogTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void ReachableGlobalCursorSpecs_resolveGoldenDatSurfaces()
{
string? datDir = ResolveDatDir();
diff --git a/tests/AcDream.App.Tests/UI/SpewBoxLayoutDumpDiagnostic.cs b/tests/AcDream.App.Tests/UI/SpewBoxLayoutDumpDiagnostic.cs
index 6d47c7ec..3d575f65 100644
--- a/tests/AcDream.App.Tests/UI/SpewBoxLayoutDumpDiagnostic.cs
+++ b/tests/AcDream.App.Tests/UI/SpewBoxLayoutDumpDiagnostic.cs
@@ -76,6 +76,7 @@ namespace AcDream.App.Tests.UI;
///
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public sealed class SpewBoxLayoutDumpDiagnostic
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.App.Tests/UI/UiDatFontBorderPixelTests.cs b/tests/AcDream.App.Tests/UI/UiDatFontBorderPixelTests.cs
index a89293e2..01588929 100644
--- a/tests/AcDream.App.Tests/UI/UiDatFontBorderPixelTests.cs
+++ b/tests/AcDream.App.Tests/UI/UiDatFontBorderPixelTests.cs
@@ -35,6 +35,7 @@ public sealed class UiDatFontBorderPixelTests
[InlineData(0x40000001u, 4u, 4u)] // 18px bold serif — SpewBox face (round 4)
[InlineData(0x40000002u, 3u, 3u)] // 14px bold serif
[InlineData(0x40000025u, 3u, 3u)] // 11px — the pre-round-4 SpewBox placeholder face
+ [Trait("Lane", "InstalledDat")]
public void RealDatFont_HasExpectedBorderPixels(uint fontId, uint expectedHorizontal, uint expectedVertical)
{
string? datDir = ResolveDatDir();
@@ -49,6 +50,7 @@ public sealed class UiDatFontBorderPixelTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void RealDatFont_EveryFontWithABackgroundAtlas_HasANonZeroBorder()
{
// docs/research/2026-08-10-retail-ui-text-style.md §1.2: "every font that
diff --git a/tests/AcDream.App.Tests/UI/UiRenderContextAlphaTests.cs b/tests/AcDream.App.Tests/UI/UiRenderContextAlphaTests.cs
index f152b8da..aed10073 100644
--- a/tests/AcDream.App.Tests/UI/UiRenderContextAlphaTests.cs
+++ b/tests/AcDream.App.Tests/UI/UiRenderContextAlphaTests.cs
@@ -237,6 +237,7 @@ public sealed class UiRenderContextAlphaTests
// -- DrawString (BitmapFont path): the same alpha chokepoint, guarded ---
[Fact]
+ [Trait("Lane", "SystemFont")]
public void FullOpacity_DrawString_BitmapFontPath_MatchesRequestedAlpha_Identity()
{
// CH6c review NIT: DrawStringDat (retail dat-font glyphs) had its own
@@ -258,6 +259,7 @@ public sealed class UiRenderContextAlphaTests
}
[Fact]
+ [Trait("Lane", "SystemFont")]
public void HalfOpacityWindow_MultipliesBitmapFontGlyphAlpha()
{
var device = new RecordingGpuDevice();
diff --git a/tests/AcDream.App.Tests/World/LiveEntityPresentationControllerTests.cs b/tests/AcDream.App.Tests/World/LiveEntityPresentationControllerTests.cs
index b5864daf..9256b77b 100644
--- a/tests/AcDream.App.Tests/World/LiveEntityPresentationControllerTests.cs
+++ b/tests/AcDream.App.Tests/World/LiveEntityPresentationControllerTests.cs
@@ -145,6 +145,7 @@ public sealed class LiveEntityPresentationControllerTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void SpellRecall_HiddenAndUnHide_RetireMagicTimelineThroughController()
{
const uint humanSetup = 0x02000001u;
diff --git a/tests/AcDream.App.Tests/World/RecallTeleportAnimationTests.cs b/tests/AcDream.App.Tests/World/RecallTeleportAnimationTests.cs
index bcdc8ee0..afc65343 100644
--- a/tests/AcDream.App.Tests/World/RecallTeleportAnimationTests.cs
+++ b/tests/AcDream.App.Tests/World/RecallTeleportAnimationTests.cs
@@ -185,6 +185,7 @@ public sealed class RecallTeleportAnimationTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledRecall_HiddenEnterWorldPublishesFinishedCyclicPoseWithoutAdvancingTime()
{
string datDir = @"C:\Turbine\Asheron's Call";
diff --git a/tests/AcDream.Bake.Tests/BakeDeterminismTests.cs b/tests/AcDream.Bake.Tests/BakeDeterminismTests.cs
index 894e742f..39f2659f 100644
--- a/tests/AcDream.Bake.Tests/BakeDeterminismTests.cs
+++ b/tests/AcDream.Bake.Tests/BakeDeterminismTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.Bake.Tests;
/// are absent (CI), same convention as
/// tests/AcDream.Core.Tests/Conformance/DatConcurrencyStressTests.
///
+[Trait("Lane", "InstalledDat")]
public sealed class BakeDeterminismTests : IDisposable {
private readonly List _tempFiles = new();
diff --git a/tests/AcDream.Content.Tests/Ap155StaticSpherePopulationMeasurementTests.cs b/tests/AcDream.Content.Tests/Ap155StaticSpherePopulationMeasurementTests.cs
index 00896777..935f9248 100644
--- a/tests/AcDream.Content.Tests/Ap155StaticSpherePopulationMeasurementTests.cs
+++ b/tests/AcDream.Content.Tests/Ap155StaticSpherePopulationMeasurementTests.cs
@@ -23,6 +23,7 @@ namespace AcDream.Content.Tests;
/// of the 3,605 "sphere-only, no cylinder" Setups the reachability sweep
/// already counted fall into exactly that trap.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Ap155StaticSpherePopulationMeasurementTests
{
[Fact]
diff --git a/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogColorTests.cs b/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogColorTests.cs
index 75666ece..447d923b 100644
--- a/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogColorTests.cs
+++ b/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogColorTests.cs
@@ -22,6 +22,7 @@ namespace AcDream.Content.Tests.CharGen;
/// ChargenAppearanceCatalogInstalledDatTests): returns green with a
/// console SKIP note when no installed dat directory is configured.
///
+[Trait("Lane", "InstalledDat")]
public sealed class ChargenAppearanceCatalogColorTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogInstalledDatTests.cs b/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogInstalledDatTests.cs
index 98c0d0a4..0c66b5ac 100644
--- a/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogInstalledDatTests.cs
+++ b/tests/AcDream.Content.Tests/CharGen/ChargenAppearanceCatalogInstalledDatTests.cs
@@ -28,6 +28,7 @@ namespace AcDream.Content.Tests.CharGen;
/// consistent with the rest of the suite rather than introducing a new
/// convention.
///
+[Trait("Lane", "InstalledDat")]
public sealed class ChargenAppearanceCatalogInstalledDatTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Content.Tests/CharGen/ChargenTableReaderInstalledDatTests.cs b/tests/AcDream.Content.Tests/CharGen/ChargenTableReaderInstalledDatTests.cs
index 60a015f5..cab1bd8f 100644
--- a/tests/AcDream.Content.Tests/CharGen/ChargenTableReaderInstalledDatTests.cs
+++ b/tests/AcDream.Content.Tests/CharGen/ChargenTableReaderInstalledDatTests.cs
@@ -14,6 +14,7 @@ namespace AcDream.Content.Tests.CharGen;
/// cleanly (with a console note) when no DAT directory is configured,
/// matching e.g. PakEquivalenceTests / RetailDatLoaderTests.
///
+[Trait("Lane", "InstalledDat")]
public sealed class ChargenTableReaderInstalledDatTests
{
// ACE ACE.Entity.Enum.HeritageGroup — the four heritages CC1's spec
diff --git a/tests/AcDream.Content.Tests/InstalledPreparedCollisionCatalogTests.cs b/tests/AcDream.Content.Tests/InstalledPreparedCollisionCatalogTests.cs
index 04bff25c..8fcb9963 100644
--- a/tests/AcDream.Content.Tests/InstalledPreparedCollisionCatalogTests.cs
+++ b/tests/AcDream.Content.Tests/InstalledPreparedCollisionCatalogTests.cs
@@ -4,6 +4,7 @@ using DatReaderWriter.Options;
namespace AcDream.Content.Tests;
+[Trait("Lane", "PreparedPackage")]
public sealed class InstalledPreparedCollisionCatalogTests
{
[Fact]
diff --git a/tests/AcDream.Content.Tests/InstalledSetupBspPrimitiveDispatchTests.cs b/tests/AcDream.Content.Tests/InstalledSetupBspPrimitiveDispatchTests.cs
index 7343f4d7..f7d96d5b 100644
--- a/tests/AcDream.Content.Tests/InstalledSetupBspPrimitiveDispatchTests.cs
+++ b/tests/AcDream.Content.Tests/InstalledSetupBspPrimitiveDispatchTests.cs
@@ -33,6 +33,7 @@ namespace AcDream.Content.Tests;
/// predicate used here.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class InstalledSetupBspPrimitiveDispatchTests
{
// EXTERNAL constants. The four bucket controls are the ones already
diff --git a/tests/AcDream.Content.Tests/InstalledSetupCollisionReachabilityTests.cs b/tests/AcDream.Content.Tests/InstalledSetupCollisionReachabilityTests.cs
index 576643a0..4a2f1686 100644
--- a/tests/AcDream.Content.Tests/InstalledSetupCollisionReachabilityTests.cs
+++ b/tests/AcDream.Content.Tests/InstalledSetupCollisionReachabilityTests.cs
@@ -12,6 +12,7 @@ namespace AcDream.Content.Tests;
/// asserts no such Setup exists, so the deletion cannot remove collision from
/// any real object.
///
+[Trait("Lane", "InstalledDat")]
public sealed class InstalledSetupCollisionReachabilityTests
{
// Positive controls. These are EXTERNAL constants, measured on 2026-08-06
diff --git a/tests/AcDream.Content.Tests/Issue334NeftetFormationCellMembershipTests.cs b/tests/AcDream.Content.Tests/Issue334NeftetFormationCellMembershipTests.cs
index a430c835..1c5a115c 100644
--- a/tests/AcDream.Content.Tests/Issue334NeftetFormationCellMembershipTests.cs
+++ b/tests/AcDream.Content.Tests/Issue334NeftetFormationCellMembershipTests.cs
@@ -42,6 +42,7 @@ namespace AcDream.Content.Tests;
/// columns 0..4 on both axes.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue334NeftetFormationCellMembershipTests
{
private const uint NeftetLandblock = 0x87640000u;
diff --git a/tests/AcDream.Content.Tests/PakEquivalenceTests.cs b/tests/AcDream.Content.Tests/PakEquivalenceTests.cs
index e1cf99c4..905b2c24 100644
--- a/tests/AcDream.Content.Tests/PakEquivalenceTests.cs
+++ b/tests/AcDream.Content.Tests/PakEquivalenceTests.cs
@@ -20,6 +20,7 @@ namespace AcDream.Content.Tests;
/// Skips cleanly when the real dats are absent (CI), matching
/// DatConcurrencyStressTests' convention.
///
+[Trait("Lane", "InstalledDat")]
public sealed class PakEquivalenceTests {
// Known-tricky GfxObj ids reused from existing conformance fixtures:
// 0x010002B4 / 0x010008A8 — #119 "[up-null] upload returned null" dump
diff --git a/tests/AcDream.Content.Tests/SolidColorTextureCacheTests.cs b/tests/AcDream.Content.Tests/SolidColorTextureCacheTests.cs
index b4b2ea3c..f8281cc8 100644
--- a/tests/AcDream.Content.Tests/SolidColorTextureCacheTests.cs
+++ b/tests/AcDream.Content.Tests/SolidColorTextureCacheTests.cs
@@ -17,6 +17,7 @@ namespace AcDream.Content.Tests;
/// construct (its ctor builds a RetailPhysicsScriptLoader from dats.Portal).
/// Skips cleanly when dats are absent, matching ContentConformanceDats convention.
///
+[Trait("Lane", "InstalledDat")]
public sealed class SolidColorTextureCacheTests {
[Fact]
public void GetOrCreateSolidColorTexture_SameColor_ReturnsSameSharedArray() {
diff --git a/tests/AcDream.Content.Tests/Spells/RetailSpellMetadataProjectorTests.cs b/tests/AcDream.Content.Tests/Spells/RetailSpellMetadataProjectorTests.cs
index 23d1a8b0..2a8517a5 100644
--- a/tests/AcDream.Content.Tests/Spells/RetailSpellMetadataProjectorTests.cs
+++ b/tests/AcDream.Content.Tests/Spells/RetailSpellMetadataProjectorTests.cs
@@ -73,6 +73,7 @@ public sealed class RetailSpellMetadataProjectorTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Load_EndOfRetailDat_ResolvesEveryLateLearnedSpellMissingFromCsv()
{
string? datDir = ResolveDatDir();
@@ -101,6 +102,7 @@ public sealed class RetailSpellMetadataProjectorTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Load_EndOfRetailDat_UsesRetailFormulaTargetsInsteadOfLegacyExportMasks()
{
string? datDir = ResolveDatDir();
diff --git a/tests/AcDream.Content.Tests/Vfx/RetailDatLoaderTests.cs b/tests/AcDream.Content.Tests/Vfx/RetailDatLoaderTests.cs
index 7594c5f6..3abf1950 100644
--- a/tests/AcDream.Content.Tests/Vfx/RetailDatLoaderTests.cs
+++ b/tests/AcDream.Content.Tests/Vfx/RetailDatLoaderTests.cs
@@ -432,6 +432,7 @@ public sealed class RetailDatLoaderTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledBlockingScripts_ParseThroughRetailShape_WhenDatsAvailable()
{
string? datDir = ResolveDatDirectory();
diff --git a/tests/AcDream.Core.Net.Tests/LiveHandshakeTests.cs b/tests/AcDream.Core.Net.Tests/LiveHandshakeTests.cs
index 52ac51d6..f60caf53 100644
--- a/tests/AcDream.Core.Net.Tests/LiveHandshakeTests.cs
+++ b/tests/AcDream.Core.Net.Tests/LiveHandshakeTests.cs
@@ -29,6 +29,7 @@ namespace AcDream.Core.Net.Tests;
/// the env-var setup are distinguishable from server errors.
///
///
+[Trait("Lane", "Live")]
public class LiveHandshakeTests
{
[Fact]
diff --git a/tests/AcDream.Core.Tests/Audio/EnvCellSoundEmitterInventoryTests.cs b/tests/AcDream.Core.Tests/Audio/EnvCellSoundEmitterInventoryTests.cs
index f9f1e24d..c0ccf4da 100644
--- a/tests/AcDream.Core.Tests/Audio/EnvCellSoundEmitterInventoryTests.cs
+++ b/tests/AcDream.Core.Tests/Audio/EnvCellSoundEmitterInventoryTests.cs
@@ -38,6 +38,7 @@ namespace AcDream.Core.Tests.Audio;
/// absent.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class EnvCellSoundEmitterInventoryTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Audio/UiSoundTableResolutionTests.cs b/tests/AcDream.Core.Tests/Audio/UiSoundTableResolutionTests.cs
index 3f7be452..11e62d90 100644
--- a/tests/AcDream.Core.Tests/Audio/UiSoundTableResolutionTests.cs
+++ b/tests/AcDream.Core.Tests/Audio/UiSoundTableResolutionTests.cs
@@ -38,6 +38,7 @@ namespace AcDream.Core.Tests.Audio;
/// installed-dat test in this suite.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class UiSoundTableResolutionTests
{
///
diff --git a/tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs b/tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs
index 43276346..7d6d4f39 100644
--- a/tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/CottageDoorwayCharacterizationTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.Core.Tests.Conformance;
/// not the master plan's loose "0031↔0170↔0171". The cottage cellar is the
/// 0x014x range (#98 fixtures); the doorway room/vestibule is in 0x017x.
///
+[Trait("Lane", "InstalledDat")]
public class CottageDoorwayCharacterizationTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/DatConcurrencyStressTests.cs b/tests/AcDream.Core.Tests/Conformance/DatConcurrencyStressTests.cs
index 542c7724..c0b0966a 100644
--- a/tests/AcDream.Core.Tests/Conformance/DatConcurrencyStressTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/DatConcurrencyStressTests.cs
@@ -39,6 +39,7 @@ namespace AcDream.Core.Tests.Conformance;
/// (e.g. dispose-during-read at teardown) or layers above the dat reader.
///
[Trait("Category", "Conformance")]
+[Trait("Lane", "InstalledDat")]
public class DatConcurrencyStressTests
{
private const int HammerThreads = 8;
diff --git a/tests/AcDream.Core.Tests/Conformance/DungeonLandblockDatProbeTests.cs b/tests/AcDream.Core.Tests/Conformance/DungeonLandblockDatProbeTests.cs
index 70d1307c..0ceeebd5 100644
--- a/tests/AcDream.Core.Tests/Conformance/DungeonLandblockDatProbeTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/DungeonLandblockDatProbeTests.cs
@@ -17,6 +17,7 @@ namespace AcDream.Core.Tests.Conformance;
/// LandBlockInfo + EnvCells? Output-only — no assertions.
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public sealed class DungeonLandblockDatProbeTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs b/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs
index 7e617e36..88e8a366 100644
--- a/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/FindCellListConformanceTests.cs
@@ -30,6 +30,7 @@ public class FindCellListConformanceTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void FindCellList_DeepInsideRoom0171_Returns0171()
{
var datDir = ConformanceDats.ResolveDatDir();
@@ -47,6 +48,7 @@ public class FindCellListConformanceTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void FindCellList_DeepInsideVestibule0170_Returns0170()
{
var datDir = ConformanceDats.ResolveDatDir();
@@ -70,6 +72,7 @@ public class FindCellListConformanceTests
/// property P1 must preserve.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void FindCellList_InVestibule_SeededFromRoom_Returns0170()
{
var datDir = ConformanceDats.ResolveDatDir();
diff --git a/tests/AcDream.Core.Tests/Conformance/HoltburgTorchFalloffProbeTests.cs b/tests/AcDream.Core.Tests/Conformance/HoltburgTorchFalloffProbeTests.cs
index dfd8ec02..9ce2922a 100644
--- a/tests/AcDream.Core.Tests/Conformance/HoltburgTorchFalloffProbeTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/HoltburgTorchFalloffProbeTests.cs
@@ -21,6 +21,7 @@ namespace AcDream.Core.Tests.Conformance;
/// separately in the decomp). Output-only — no assertions; read the log.
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public sealed class HoltburgTorchFalloffProbeTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/Issue107SpawnDiagnosticTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue107SpawnDiagnosticTests.cs
index e171b324..bf9f3e7a 100644
--- a/tests/AcDream.Core.Tests/Conformance/Issue107SpawnDiagnosticTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/Issue107SpawnDiagnosticTests.cs
@@ -27,6 +27,7 @@ namespace AcDream.Core.Tests.Conformance;
/// find_visible_child_cell also cannot recover a cross-building claim and
/// falls to seen_outside → adjust_to_outside, acclient :280037).
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue107SpawnDiagnosticTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/Issue112MembershipTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue112MembershipTests.cs
index 5141770e..6d728430 100644
--- a/tests/AcDream.Core.Tests/Conformance/Issue112MembershipTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/Issue112MembershipTests.cs
@@ -19,6 +19,7 @@ namespace AcDream.Core.Tests.Conformance;
/// (pc:308788-308825). These tests pin the replacement semantics against the
/// real dats.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue112MembershipTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs
index 010b13c5..c14b3d02 100644
--- a/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/Issue113DoorVanishDiagnosticTests.cs
@@ -21,6 +21,7 @@ namespace AcDream.Core.Tests.Conformance;
/// carry polygon references in properties the walk missed (portal-type
/// nodes / leaf subclasses)? Pure diagnostic — no production code.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue113DoorVanishDiagnosticTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/Issue113PhantomStairsDumpTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue113PhantomStairsDumpTests.cs
index 91545d8c..1d44bc9a 100644
--- a/tests/AcDream.Core.Tests/Conformance/Issue113PhantomStairsDumpTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/Issue113PhantomStairsDumpTests.cs
@@ -24,6 +24,7 @@ namespace AcDream.Core.Tests.Conformance;
/// interior cell's Position + world AABB + SeenOutside flag + stair signature
/// (distinct horizontal-face heights), and containment of the two key points.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue113PhantomStairsDumpTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/Issue119TowerDumpTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue119TowerDumpTests.cs
index 6f011285..c8f09929 100644
--- a/tests/AcDream.Core.Tests/Conformance/Issue119TowerDumpTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/Issue119TowerDumpTests.cs
@@ -24,6 +24,7 @@ namespace AcDream.Core.Tests.Conformance;
/// static object (id + position) — the barrel candidate and the stair
/// owners read directly off the output.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue119TowerDumpTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/Issue119UpNullGfxObjDumpTests.cs b/tests/AcDream.Core.Tests/Conformance/Issue119UpNullGfxObjDumpTests.cs
index 0b123199..51a23fc3 100644
--- a/tests/AcDream.Core.Tests/Conformance/Issue119UpNullGfxObjDumpTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/Issue119UpNullGfxObjDumpTests.cs
@@ -23,6 +23,7 @@ namespace AcDream.Core.Tests.Conformance;
/// ObjectMeshManager in MP1a)
/// so the zeroing gate reads directly off the output.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue119UpNullGfxObjDumpTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/StipplingSurfaceEquivalenceTests.cs b/tests/AcDream.Core.Tests/Conformance/StipplingSurfaceEquivalenceTests.cs
index db553c80..ccb5362a 100644
--- a/tests/AcDream.Core.Tests/Conformance/StipplingSurfaceEquivalenceTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/StipplingSurfaceEquivalenceTests.cs
@@ -30,6 +30,7 @@ namespace AcDream.Core.Tests.Conformance;
/// Violations of (b) on PLAIN OBJECT GfxObjs are allowed — retail's bypass
/// draws solid batches for non-building/non-cell meshes, and so do we.
///
+[Trait("Lane", "InstalledDat")]
public sealed class StipplingSurfaceEquivalenceTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/ThresholdDivergenceDiagnosticTests.cs b/tests/AcDream.Core.Tests/Conformance/ThresholdDivergenceDiagnosticTests.cs
index 860b9946..3b415fd4 100644
--- a/tests/AcDream.Core.Tests/Conformance/ThresholdDivergenceDiagnosticTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/ThresholdDivergenceDiagnosticTests.cs
@@ -14,6 +14,7 @@ namespace AcDream.Core.Tests.Conformance;
/// (real pick-criterion divergence vs a test/sphere artifact).
///
[Trait("Purpose", "Diagnostic")]
+[Trait("Lane", "InstalledDat")]
public class ThresholdDivergenceDiagnosticTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Conformance/ThresholdPortalCrossingReplayTests.cs b/tests/AcDream.Core.Tests/Conformance/ThresholdPortalCrossingReplayTests.cs
index 356f4396..6bca27a4 100644
--- a/tests/AcDream.Core.Tests/Conformance/ThresholdPortalCrossingReplayTests.cs
+++ b/tests/AcDream.Core.Tests/Conformance/ThresholdPortalCrossingReplayTests.cs
@@ -27,6 +27,7 @@ namespace AcDream.Core.Tests.Conformance;
/// building-cell cache. The outdoor-involving segments (0031↔0170) need the landcell +
/// building portal and are a follow-up.
///
+[Trait("Lane", "InstalledDat")]
public class ThresholdPortalCrossingReplayTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Input/RetailActionIdentityRoundTripTests.cs b/tests/AcDream.Core.Tests/Input/RetailActionIdentityRoundTripTests.cs
index 480c6e15..0d01a329 100644
--- a/tests/AcDream.Core.Tests/Input/RetailActionIdentityRoundTripTests.cs
+++ b/tests/AcDream.Core.Tests/Input/RetailActionIdentityRoundTripTests.cs
@@ -54,6 +54,7 @@ namespace AcDream.Core.Tests.Input;
/// here. Reported, not silently resolved either way.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class RetailActionIdentityRoundTripTests
{
/// Actions with a citation-backed, pre-existing reason their DAT-union
diff --git a/tests/AcDream.Core.Tests/Input/RetailActionMapReaderTests.cs b/tests/AcDream.Core.Tests/Input/RetailActionMapReaderTests.cs
index 211993ec..7bb93d7f 100644
--- a/tests/AcDream.Core.Tests/Input/RetailActionMapReaderTests.cs
+++ b/tests/AcDream.Core.Tests/Input/RetailActionMapReaderTests.cs
@@ -204,6 +204,7 @@ public sealed class RetailActionMapReaderTests
/// Live-DAT conformance: pins the exact shape of the installed
/// client_portal.dat/client_local_English.dat ActionMap +
/// MasterInputMap objects. Skips cleanly when the dats are unavailable.
+[Trait("Lane", "InstalledDat")]
public sealed class RetailActionMapReader_LiveDatTests
{
[Fact]
diff --git a/tests/AcDream.Core.Tests/Physics/Ap157SortingSphereFloodMeasurementTests.cs b/tests/AcDream.Core.Tests/Physics/Ap157SortingSphereFloodMeasurementTests.cs
index 347b9e0f..6cbc4d09 100644
--- a/tests/AcDream.Core.Tests/Physics/Ap157SortingSphereFloodMeasurementTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Ap157SortingSphereFloodMeasurementTests.cs
@@ -59,6 +59,7 @@ namespace AcDream.Core.Tests.Physics;
/// the flood-sphere list, not a subset or approximation of it.
///
///
+[Trait("Lane", "InstalledDat")]
public sealed class Ap157SortingSphereFloodMeasurementTests
{
/// Arbitrary non-zero landblock id — only its prefix matters for
diff --git a/tests/AcDream.Core.Tests/Physics/BoxIntersectsCellBspDifferentialTests.cs b/tests/AcDream.Core.Tests/Physics/BoxIntersectsCellBspDifferentialTests.cs
index 1a8625e2..7666abfd 100644
--- a/tests/AcDream.Core.Tests/Physics/BoxIntersectsCellBspDifferentialTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/BoxIntersectsCellBspDifferentialTests.cs
@@ -189,6 +189,7 @@ public sealed class BoxIntersectsCellBspDifferentialTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledDat_RandomizedBoxSweepOverEnvCellContainmentBsps_HasZeroMismatch()
{
string? datDirectory = ConformanceDats.ResolveDatDir();
diff --git a/tests/AcDream.Core.Tests/Physics/CameraCornerSealReplayTests.cs b/tests/AcDream.Core.Tests/Physics/CameraCornerSealReplayTests.cs
index ff5cf518..4676ac78 100644
--- a/tests/AcDream.Core.Tests/Physics/CameraCornerSealReplayTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/CameraCornerSealReplayTests.cs
@@ -38,6 +38,7 @@ namespace AcDream.Core.Tests.Physics;
/// L20104 / L20224 / L20386 (door-exit) + L23035 / L81340 / L87958 (corner press);
/// pivot = player + (0,0,1.5) per RetailChaseCamera.PivotHeight.
///
+[Trait("Lane", "InstalledDat")]
public class CameraCornerSealReplayTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/CellTransitFindTransitCellsBoxTests.cs b/tests/AcDream.Core.Tests/Physics/CellTransitFindTransitCellsBoxTests.cs
index 29ddbce0..ad7e0671 100644
--- a/tests/AcDream.Core.Tests/Physics/CellTransitFindTransitCellsBoxTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/CellTransitFindTransitCellsBoxTests.cs
@@ -263,6 +263,7 @@ public sealed class CellTransitFindTransitCellsBoxTests
/// for the exact counts from this run.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledDat_RandomizedPartSweepNearRealPortals_PostFixMembershipIsSubsetOfPreFix()
{
string? datDirectory = ConformanceDats.ResolveDatDir();
diff --git a/tests/AcDream.Core.Tests/Physics/CellTransitTests.cs b/tests/AcDream.Core.Tests/Physics/CellTransitTests.cs
index 92d2ca31..ce198da1 100644
--- a/tests/AcDream.Core.Tests/Physics/CellTransitTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/CellTransitTests.cs
@@ -28,6 +28,7 @@ namespace AcDream.Core.Tests.Physics;
/// semantics on real Holtburg dat geometry.
///
///
+[Trait("Lane", "InstalledDat")]
public class CellTransitTests
{
[Fact]
diff --git a/tests/AcDream.Core.Tests/Physics/DoorBugTrajectoryReplayTests.cs b/tests/AcDream.Core.Tests/Physics/DoorBugTrajectoryReplayTests.cs
index 875afd23..208324fe 100644
--- a/tests/AcDream.Core.Tests/Physics/DoorBugTrajectoryReplayTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/DoorBugTrajectoryReplayTests.cs
@@ -82,6 +82,7 @@ public class DoorBugTrajectoryReplayTests
/// door's outdoor cell when production's doesn't.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void LiveCompare_DoorOffCenterWalkthrough_Tick13558()
{
var datDir = ResolveDatDir();
@@ -117,6 +118,7 @@ public class DoorBugTrajectoryReplayTests
/// registration itself is wrong.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void LiveCompare_DoorBlocksFromOutside_Tick22760()
{
var datDir = ResolveDatDir();
@@ -159,6 +161,7 @@ public class DoorBugTrajectoryReplayTests
/// hard-stopped with cn=(0,0,1). Always passes; read the console dump.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Diagnostic_Tick22760_DumpEngineInternals()
{
var datDir = ResolveDatDir();
@@ -211,6 +214,7 @@ public class DoorBugTrajectoryReplayTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Diagnostic_Tick13558_DumpEngineInternals()
{
var datDir = ResolveDatDir();
@@ -272,6 +276,7 @@ public class DoorBugTrajectoryReplayTests
/// portal traversal IS the bug.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void FindTransitCellsSphere_IndoorExitPortal_AddsOutsideForCapturedSpherePos()
{
var datDir = ResolveDatDir();
@@ -472,6 +477,7 @@ public class DoorBugTrajectoryReplayTests
///
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InsideOut_Tick3254_WithCottageWalls_ShouldBlock()
{
var datDir = ResolveDatDir();
@@ -543,6 +549,7 @@ public class DoorBugTrajectoryReplayTests
/// (133.5, 17.10) to end up at X > 133.5 Y > 17.10, bug reproduced.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void CornerSlide_AlcoveEastToCottageNorth_ShouldBlock()
{
var datDir = ResolveDatDir();
@@ -770,6 +777,7 @@ public class DoorBugTrajectoryReplayTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Geometric_DoorSlabAtSphereHeight_OverlapsInZ()
{
var datDir = ResolveDatDir();
@@ -821,6 +829,7 @@ public class DoorBugTrajectoryReplayTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Directional_OutsideIn_SouthApproach_BlocksAtSlabSouthFace()
{
var datDir = ResolveDatDir();
@@ -848,6 +857,7 @@ public class DoorBugTrajectoryReplayTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Directional_InsideOut_NorthApproach_BlocksAtSlabNorthFace()
{
var datDir = ResolveDatDir();
diff --git a/tests/AcDream.Core.Tests/Physics/DoorCollisionApparatusTests.cs b/tests/AcDream.Core.Tests/Physics/DoorCollisionApparatusTests.cs
index 396e1c0f..95561d0c 100644
--- a/tests/AcDream.Core.Tests/Physics/DoorCollisionApparatusTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/DoorCollisionApparatusTests.cs
@@ -40,6 +40,7 @@ namespace AcDream.Core.Tests.Physics;
/// CI stays green. Local developer machines always have it.
///
///
+[Trait("Lane", "InstalledDat")]
public class DoorCollisionApparatusTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/DoorSetupGfxObjInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/DoorSetupGfxObjInspectionTests.cs
index f3e72b9a..b59e20d9 100644
--- a/tests/AcDream.Core.Tests/Physics/DoorSetupGfxObjInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/DoorSetupGfxObjInspectionTests.cs
@@ -26,6 +26,7 @@ namespace AcDream.Core.Tests.Physics;
/// keeps CI green. Local developer runs always have it.
///
///
+[Trait("Lane", "InstalledDat")]
public class DoorSetupGfxObjInspectionTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/FlatBspQueryDifferentialTests.cs b/tests/AcDream.Core.Tests/Physics/FlatBspQueryDifferentialTests.cs
index 99a9eee1..26a9d2f6 100644
--- a/tests/AcDream.Core.Tests/Physics/FlatBspQueryDifferentialTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/FlatBspQueryDifferentialTests.cs
@@ -412,6 +412,7 @@ public sealed class FlatBspQueryDifferentialTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void InstalledDat_LargeRandomizedSweep_HasZeroBitMismatch()
{
string? datDirectory = ConformanceDats.ResolveDatDir();
diff --git a/tests/AcDream.Core.Tests/Physics/FlatCollisionInstalledDatTests.cs b/tests/AcDream.Core.Tests/Physics/FlatCollisionInstalledDatTests.cs
index 43ed3820..9265d142 100644
--- a/tests/AcDream.Core.Tests/Physics/FlatCollisionInstalledDatTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/FlatCollisionInstalledDatTests.cs
@@ -9,6 +9,7 @@ using Xunit.Abstractions;
namespace AcDream.Core.Tests.Physics;
+[Trait("Lane", "InstalledDat")]
public sealed class FlatCollisionInstalledDatTests
{
private readonly ITestOutputHelper _output;
diff --git a/tests/AcDream.Core.Tests/Physics/HumanoidMotionTableRootMotionTests.cs b/tests/AcDream.Core.Tests/Physics/HumanoidMotionTableRootMotionTests.cs
index 4f47eee9..256aee0d 100644
--- a/tests/AcDream.Core.Tests/Physics/HumanoidMotionTableRootMotionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/HumanoidMotionTableRootMotionTests.cs
@@ -15,6 +15,7 @@ namespace AcDream.Core.Tests.Physics;
/// The packet-driven remote mover must use these values, not a velocity guessed
/// from the interpreted command.
///
+[Trait("Lane", "InstalledDat")]
public sealed class HumanoidMotionTableRootMotionTests
{
private const uint HumanoidMotionTable = 0x09000001u;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue108CellarAscentViewerReplayTests.cs b/tests/AcDream.Core.Tests/Physics/Issue108CellarAscentViewerReplayTests.cs
index abd691a8..8bdf42ad 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue108CellarAscentViewerReplayTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue108CellarAscentViewerReplayTests.cs
@@ -66,6 +66,7 @@ namespace AcDream.Core.Tests.Physics;
/// eye projects into the aperture band at y 9.8–17) paints the doorway.
/// These tests stay as the characterization pin for the healthy layer.
///
+[Trait("Lane", "InstalledDat")]
public class Issue108CellarAscentViewerReplayTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamInspectionTests.cs
index 6a63d73c..1fb4d502 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamInspectionTests.cs
@@ -20,6 +20,7 @@ namespace AcDream.Core.Tests.Physics;
/// (normal ≈ ±X at the portal's local X) — i.e., are portal-sealing polys in
/// our collision set where retail filters them?
///
+[Trait("Lane", "InstalledDat")]
public class Issue137CorridorSeamInspectionTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamReplayTests.cs b/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamReplayTests.cs
index 3724db77..8c91fda5 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamReplayTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue137CorridorSeamReplayTests.cs
@@ -38,6 +38,7 @@ namespace AcDream.Core.Tests.Physics;
/// running must keep advancing (no absorbing wedge).
///
///
+[Trait("Lane", "InstalledDat")]
public class Issue137CorridorSeamReplayTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue147ArwicBuildingsDumpTests.cs b/tests/AcDream.Core.Tests/Physics/Issue147ArwicBuildingsDumpTests.cs
index 610b87d2..793bb47e 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue147ArwicBuildingsDumpTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue147ArwicBuildingsDumpTests.cs
@@ -17,6 +17,7 @@ namespace AcDream.Core.Tests.Physics;
/// (a separate shadow-object collision path). Dat-data-dependent; SKIPs cleanly
/// without ACDREAM_DAT_DIR / the real dats.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue147ArwicBuildingsDumpTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue175HubDoorPoseInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/Issue175HubDoorPoseInspectionTests.cs
index 6cd9bf4f..7d772ebe 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue175HubDoorPoseInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue175HubDoorPoseInspectionTests.cs
@@ -39,6 +39,7 @@ public class Issue175HubDoorPoseInspectionTests
private const uint HubDoorSetupId = 0x02000C9Du;
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void HubDoorSetup_PlacementVsMotionPose_DatInspection()
{
var datDir = Env.GetEnvironmentVariable("ACDREAM_DAT_DIR")
@@ -161,6 +162,7 @@ public class Issue175HubDoorPoseInspectionTests
/// NonCombat/Ready) and asserts the derivation actually resolves a pose.
///
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void MotionTablePose_DefaultState_ResolvesOnRealTable()
{
var datDir = Env.GetEnvironmentVariable("ACDREAM_DAT_DIR")
diff --git a/tests/AcDream.Core.Tests/Physics/Issue176177SeamTransitLagTests.cs b/tests/AcDream.Core.Tests/Physics/Issue176177SeamTransitLagTests.cs
index 33bf9952..61e1daad 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue176177SeamTransitLagTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue176177SeamTransitLagTests.cs
@@ -24,6 +24,7 @@ namespace AcDream.Core.Tests.Physics;
/// stair pop). This replay measures OUR resolver's flip point across the
/// x=85 seam in a controlled run.
///
+[Trait("Lane", "InstalledDat")]
public class Issue176177SeamTransitLagTests
{
private const uint SeamCellWest = 0x8A02016Eu; // x 75..85
diff --git a/tests/AcDream.Core.Tests/Physics/Issue180CorridorSweepHysteresisReplayTests.cs b/tests/AcDream.Core.Tests/Physics/Issue180CorridorSweepHysteresisReplayTests.cs
index 8a8ddb46..12423967 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue180CorridorSweepHysteresisReplayTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue180CorridorSweepHysteresisReplayTests.cs
@@ -35,6 +35,7 @@ namespace AcDream.Core.Tests.Physics;
/// 3. the clipped eye is the CONSTANT surface-contact point (pre-fix it
/// tracked the target one step back: eyeBack = s − ~0.27).
///
+[Trait("Lane", "InstalledDat")]
public class Issue180CorridorSweepHysteresisReplayTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue186ConnectorCellGeometryInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/Issue186ConnectorCellGeometryInspectionTests.cs
index dcf8d68f..66f12691 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue186ConnectorCellGeometryInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue186ConnectorCellGeometryInspectionTests.cs
@@ -20,6 +20,7 @@ namespace AcDream.Core.Tests.Physics;
/// bare connector? And does it carry collision geometry (so the camera sweep would
/// hard-stop) or none (so the boom coasts to a degenerate spot)? Skips without the dat.
///
+[Trait("Lane", "InstalledDat")]
public class Issue186ConnectorCellGeometryInspectionTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Physics/Issue188FadingDoorMotionTableInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/Issue188FadingDoorMotionTableInspectionTests.cs
index a78498d1..e3c0d176 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue188FadingDoorMotionTableInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue188FadingDoorMotionTableInspectionTests.cs
@@ -74,6 +74,7 @@ public class Issue188FadingDoorMotionTableInspectionTests
}
[Fact]
+ [Trait("Lane", "InstalledDat")]
public void Dump_PedestalWeakSpot_MotionTable_HookContents()
{
var datDir = DatDir();
diff --git a/tests/AcDream.Core.Tests/Physics/Issue337NeftetRockGeometryInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/Issue337NeftetRockGeometryInspectionTests.cs
index b8e9daf9..f19c168c 100644
--- a/tests/AcDream.Core.Tests/Physics/Issue337NeftetRockGeometryInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/Issue337NeftetRockGeometryInspectionTests.cs
@@ -38,6 +38,7 @@ namespace AcDream.Core.Tests.Physics;
///
/// Dat-data dependent; SKIPs cleanly without ACDREAM_DAT_DIR.
///
+[Trait("Lane", "InstalledDat")]
public sealed class Issue337NeftetRockGeometryInspectionTests
{
private const uint Landblock = 0x8766_0000u;
diff --git a/tests/AcDream.Core.Tests/Physics/MotionCommandCatalogDatTests.cs b/tests/AcDream.Core.Tests/Physics/MotionCommandCatalogDatTests.cs
index da169456..80e7d728 100644
--- a/tests/AcDream.Core.Tests/Physics/MotionCommandCatalogDatTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/MotionCommandCatalogDatTests.cs
@@ -40,6 +40,7 @@ namespace AcDream.Core.Tests.Physics;
/// present (CI has no local AC install).
///
///
+[Trait("Lane", "InstalledDat")]
public class MotionCommandCatalogDatTests
{
///
diff --git a/tests/AcDream.Core.Tests/Physics/RestrictionObjPrevalenceInspectionTests.cs b/tests/AcDream.Core.Tests/Physics/RestrictionObjPrevalenceInspectionTests.cs
index dbd8b71d..0198c18b 100644
--- a/tests/AcDream.Core.Tests/Physics/RestrictionObjPrevalenceInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Physics/RestrictionObjPrevalenceInspectionTests.cs
@@ -18,6 +18,7 @@ namespace AcDream.Core.Tests.Physics;
/// when the installed DATs are absent (CI), following the
/// DoorSetupGfxObjInspectionTests pattern.
///
+[Trait("Lane", "InstalledDat")]
public sealed class RestrictionObjPrevalenceInspectionTests
{
private readonly ITestOutputHelper _output;
diff --git a/tests/AcDream.Core.Tests/Rendering/Issue176177DungeonSeamInspectionTests.cs b/tests/AcDream.Core.Tests/Rendering/Issue176177DungeonSeamInspectionTests.cs
index 54064199..7c109789 100644
--- a/tests/AcDream.Core.Tests/Rendering/Issue176177DungeonSeamInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Rendering/Issue176177DungeonSeamInspectionTests.cs
@@ -31,6 +31,7 @@ namespace AcDream.Core.Tests.Rendering;
/// CellPortal.PolygonId indexes CellStruct.Polygons (VISUAL), never
/// PhysicsPolygons — same ids in both tables are unrelated polygons.
///
+[Trait("Lane", "InstalledDat")]
public class Issue176177DungeonSeamInspectionTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Rendering/Issue93TownNetworkFountainRoomLightInspectionTests.cs b/tests/AcDream.Core.Tests/Rendering/Issue93TownNetworkFountainRoomLightInspectionTests.cs
index cc820caf..784efdf8 100644
--- a/tests/AcDream.Core.Tests/Rendering/Issue93TownNetworkFountainRoomLightInspectionTests.cs
+++ b/tests/AcDream.Core.Tests/Rendering/Issue93TownNetworkFountainRoomLightInspectionTests.cs
@@ -26,6 +26,7 @@ namespace AcDream.Core.Tests.Rendering;
/// fountain room and its immediate neighbors observed this session, so the answer
/// is read from the dat directly instead of inferred from aggregate counts.
///
+[Trait("Lane", "InstalledDat")]
public class Issue93TownNetworkFountainRoomLightInspectionTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs b/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs
index c02f7cc2..c4deed3d 100644
--- a/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs
+++ b/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs
@@ -24,6 +24,7 @@ namespace AcDream.Core.Tests.Terrain;
/// the directory doesn't exist, the test logs a SKIP and passes — keeps CI
/// (no dat data) green while still firing locally on every developer run.
///
+[Trait("Lane", "InstalledDat")]
public class TerrainModernConformanceTests
{
private readonly ITestOutputHelper _out;
diff --git a/tests/AcDream.Headless.Tests/HeadlessCredentialResolverTests.cs b/tests/AcDream.Headless.Tests/HeadlessCredentialResolverTests.cs
index f21a79fb..97258dd0 100644
--- a/tests/AcDream.Headless.Tests/HeadlessCredentialResolverTests.cs
+++ b/tests/AcDream.Headless.Tests/HeadlessCredentialResolverTests.cs
@@ -122,6 +122,7 @@ public sealed class HeadlessCredentialResolverTests
}
[Fact]
+ [Trait("Lane", "Linux")]
public void LinuxRejectsGroupOrOtherCredentialPermissions()
{
if (!OperatingSystem.IsLinux())
diff --git a/tests/AcDream.Launcher.Core.Tests/Launching/LauncherProcessSupervisorTests.cs b/tests/AcDream.Launcher.Core.Tests/Launching/LauncherProcessSupervisorTests.cs
index ae66fb73..f4409444 100644
--- a/tests/AcDream.Launcher.Core.Tests/Launching/LauncherProcessSupervisorTests.cs
+++ b/tests/AcDream.Launcher.Core.Tests/Launching/LauncherProcessSupervisorTests.cs
@@ -9,6 +9,7 @@ namespace AcDream.Launcher.Core.Tests.Launching;
public sealed class LauncherProcessSupervisorTests
{
[Fact]
+ [Trait("Lane", "Windows")]
public void WindowsFactoryUsesNativeProcessGroupsOnlyForConsoleChildren()
{
if (!OperatingSystem.IsWindows())
@@ -148,6 +149,7 @@ public sealed class LauncherProcessSupervisorTests
}
[Fact]
+ [Trait("Lane", "Linux")]
public void GracefulStopSignalSendsSigintToARealChildOnLinux()
{
// Review finding F3, proven end to end against the real
@@ -221,6 +223,7 @@ public sealed class LauncherProcessSupervisorTests
}
[Fact]
+ [Trait("Lane", "Windows")]
public async Task WindowsCtrlBreakStopsOnlyTheTargetProcessGroupWithoutKill()
{
if (!OperatingSystem.IsWindows())
@@ -316,6 +319,7 @@ public sealed class LauncherProcessSupervisorTests
}
[Fact]
+ [Trait("Lane", "Windows")]
public async Task WindowsConsolelessParentStillTargetsDistinctChildProcessGroups()
{
if (!OperatingSystem.IsWindows())
@@ -655,6 +659,7 @@ public sealed class LauncherProcessSupervisorTests
}
[Fact]
+ [Trait("Lane", "Windows")]
public async Task RealChildStderrIsCapturedForTheWindowsNativeConsolePath()
{
// Fix #406 sibling gap: on Windows, console-capable children
diff --git a/tests/AcDream.Launcher.Core.Tests/Orchestration/LauncherExecutableSetTests.cs b/tests/AcDream.Launcher.Core.Tests/Orchestration/LauncherExecutableSetTests.cs
index a8442f65..03e5adc6 100644
--- a/tests/AcDream.Launcher.Core.Tests/Orchestration/LauncherExecutableSetTests.cs
+++ b/tests/AcDream.Launcher.Core.Tests/Orchestration/LauncherExecutableSetTests.cs
@@ -78,6 +78,7 @@ public sealed class LauncherExecutableSetTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Linux")]
public void LinuxRequiresExecutePermissionForBothCoDeployedHosts()
{
if (!OperatingSystem.IsLinux())
@@ -118,6 +119,7 @@ public sealed class LauncherExecutableSetTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Windows")]
public void WindowsPreservesExistenceOnlyAvailability()
{
if (!OperatingSystem.IsWindows())
diff --git a/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileHardeningTests.cs b/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileHardeningTests.cs
index 2da292a4..7994bdeb 100644
--- a/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileHardeningTests.cs
+++ b/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileHardeningTests.cs
@@ -128,6 +128,7 @@ public sealed class LauncherProfileHardeningTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Linux")]
public void LinuxLoadNormalizesAnExistingCredentialFileTo0600BeforeReading()
{
if (!OperatingSystem.IsLinux())
diff --git a/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileStoreTests.cs b/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileStoreTests.cs
index e02072ad..72eab62c 100644
--- a/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileStoreTests.cs
+++ b/tests/AcDream.Launcher.Core.Tests/Profiles/LauncherProfileStoreTests.cs
@@ -317,6 +317,7 @@ public sealed class LauncherProfileStoreTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Linux")]
public void SaveSetsOwnerOnlyPermissionsOnLinux()
{
// Linux-conditional: 0600 is a Linux-only hygiene step (spec §5,
@@ -361,6 +362,7 @@ public sealed class LauncherProfileStoreTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Linux")]
public void TempCredentialFileIsOwnerOnlyFromItsFirstObservableLinuxState()
{
// Deterministic proof of the exact production create path: inspect
diff --git a/tests/AcDream.Launcher.Core.Tests/Status/StatusFileTailerTests.cs b/tests/AcDream.Launcher.Core.Tests/Status/StatusFileTailerTests.cs
index 4f9314aa..5e3b31bd 100644
--- a/tests/AcDream.Launcher.Core.Tests/Status/StatusFileTailerTests.cs
+++ b/tests/AcDream.Launcher.Core.Tests/Status/StatusFileTailerTests.cs
@@ -157,6 +157,7 @@ public sealed class StatusFileTailerTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Windows")]
public void ReadNewEventsReturnsEmptyRatherThanThrowingOnASharingViolation()
{
// A deterministic proxy for the File.Exists -> new FileStream
diff --git a/tests/AcDream.Launcher.Core.Tests/Updates/ClientVersionStoreTests.cs b/tests/AcDream.Launcher.Core.Tests/Updates/ClientVersionStoreTests.cs
index ede382c9..9b9322c1 100644
--- a/tests/AcDream.Launcher.Core.Tests/Updates/ClientVersionStoreTests.cs
+++ b/tests/AcDream.Launcher.Core.Tests/Updates/ClientVersionStoreTests.cs
@@ -178,6 +178,7 @@ public sealed class ClientVersionStoreTests : IDisposable
}
[Fact]
+ [Trait("Lane", "Linux")]
public async Task LinuxTreatsNonCanonicalInstallJsonCasingAsUnrecordedContent()
{
if (!OperatingSystem.IsLinux())
diff --git a/tests/AcDream.Launcher.Tests/MainWindowViewTests.cs b/tests/AcDream.Launcher.Tests/MainWindowViewTests.cs
index 0fd62668..e01a0dce 100644
--- a/tests/AcDream.Launcher.Tests/MainWindowViewTests.cs
+++ b/tests/AcDream.Launcher.Tests/MainWindowViewTests.cs
@@ -19,8 +19,8 @@ namespace AcDream.Launcher.Tests;
/// generated InitializeComponent()) reached the user gate through
/// 14,012 green tests that were all ViewModel-only.
///
-/// Every test here constructs a real against the
-/// real compiled XAML and drives it exactly the way App.axaml.cs
+/// The Avalonia test constructs real instances against
+/// the compiled XAML and drives them exactly the way App.axaml.cs
/// does: assign a live as
/// DataContext, then exercise the modal open/close paths that
/// dereference the named controls (the bug class lives in
@@ -28,7 +28,7 @@ namespace AcDream.Launcher.Tests;
/// FocusActiveModal). That focus work is queued via
/// Dispatcher.UIThread.Post, so every test pumps the headless
/// dispatcher with before asserting — a
-/// test that only sets a property and asserts would pass vacuously
+/// phase that only sets a property and asserts would pass vacuously
/// without ever running FocusActiveModal.
///
public sealed class MainWindowViewTests
@@ -49,7 +49,22 @@ public sealed class MainWindowViewTests
];
[AvaloniaFact]
- public void EveryExplicitlyNamedControlIsAssignedAfterConstruction()
+ public async Task CompiledMarkupAndEveryModalFocusPathRunInOneOwnedAvaloniaSession()
+ {
+ // Avalonia's headless compositor is thread-affine. Keep the complete
+ // MainWindow matrix inside one runner-owned application session so
+ // xUnit cannot tear one compositor down on a different worker while
+ // starting the next scenario. Each named method remains a separate
+ // assertion phase for readable failure stacks.
+ EveryExplicitlyNamedControlIsAssignedAfterConstruction();
+ ReflectionSweepOfEveryXNameInMarkupFindsANonNullBackingField();
+ OpeningEveryEditorKindFocusesItsPrimaryFieldAndClosingRunsTheFallbackWithoutThrowing();
+ OpeningAndClosingTheFirstRunWizardFocusesAndRunsTheCloseFallbackWithoutThrowing();
+ await OpeningAndClosingTheUpdatePromptFocusesAndRunsTheCloseFallbackWithoutThrowing();
+ ClosingAModalRestoresThePreviouslyFocusedControlWithoutThrowing();
+ }
+
+ private static void EveryExplicitlyNamedControlIsAssignedAfterConstruction()
{
var window = new MainWindow();
@@ -66,8 +81,7 @@ public sealed class MainWindowViewTests
}
}
- [AvaloniaFact]
- public void ReflectionSweepOfEveryXNameInMarkupFindsANonNullBackingField()
+ private static void ReflectionSweepOfEveryXNameInMarkupFindsANonNullBackingField()
{
string markupPath = Path.Combine(
FindRepositoryRoot(),
@@ -114,8 +128,7 @@ public sealed class MainWindowViewTests
}
}
- [AvaloniaFact]
- public void OpeningEveryEditorKindFocusesItsPrimaryFieldAndClosingRunsTheFallbackWithoutThrowing()
+ private static void OpeningEveryEditorKindFocusesItsPrimaryFieldAndClosingRunsTheFallbackWithoutThrowing()
{
(ProfileEditorKind Kind, string FocusFieldName)[] cases =
[
@@ -168,8 +181,7 @@ public sealed class MainWindowViewTests
}
}
- [AvaloniaFact]
- public void OpeningAndClosingTheFirstRunWizardFocusesAndRunsTheCloseFallbackWithoutThrowing()
+ private static void OpeningAndClosingTheFirstRunWizardFocusesAndRunsTheCloseFallbackWithoutThrowing()
{
using LauncherWindowViewModel viewModel = CreateViewModel();
var window = new MainWindow { DataContext = viewModel };
@@ -198,8 +210,7 @@ public sealed class MainWindowViewTests
}
}
- [AvaloniaFact]
- public async Task OpeningAndClosingTheUpdatePromptFocusesAndRunsTheCloseFallbackWithoutThrowing()
+ private static async Task OpeningAndClosingTheUpdatePromptFocusesAndRunsTheCloseFallbackWithoutThrowing()
{
using LauncherWindowViewModel viewModel = CreateViewModel();
var window = new MainWindow { DataContext = viewModel };
@@ -228,8 +239,7 @@ public sealed class MainWindowViewTests
}
}
- [AvaloniaFact]
- public void ClosingAModalRestoresThePreviouslyFocusedControlWithoutThrowing()
+ private static void ClosingAModalRestoresThePreviouslyFocusedControlWithoutThrowing()
{
using LauncherWindowViewModel viewModel = CreateViewModel();
var window = new MainWindow { DataContext = viewModel };
diff --git a/tools/audit-test-inventory.ps1 b/tools/audit-test-inventory.ps1
index 5eb93737..a0ef134a 100644
--- a/tools/audit-test-inventory.ps1
+++ b/tools/audit-test-inventory.ps1
@@ -354,6 +354,29 @@ $summary = [ordered]@{
KnownFailureMethods = @($orderedRecords | Where-Object {
$_.Traits -contains 'Status, KnownFailure'
}).Count
+ LaneMethods = [ordered]@{
+ InstalledDat = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, InstalledDat'
+ }).Count
+ PreparedPackage = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, PreparedPackage'
+ }).Count
+ Live = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, Live'
+ }).Count
+ Manual = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, Manual'
+ }).Count
+ Windows = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, Windows'
+ }).Count
+ Linux = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, Linux'
+ }).Count
+ SystemFont = @($orderedRecords | Where-Object {
+ $_.Traits -contains 'Lane, SystemFont'
+ }).Count
+ }
ThreadSleepMethods = @($orderedRecords | Where-Object { $_.HasThreadSleep }).Count
TaskDelayMethods = @($orderedRecords | Where-Object { $_.HasTaskDelay }).Count
DirectEnvironmentVariableMethods = @($orderedRecords | Where-Object {
diff --git a/tools/run-release-gate.ps1 b/tools/run-release-gate.ps1
index d434c13b..6665a7d9 100644
--- a/tools/run-release-gate.ps1
+++ b/tools/run-release-gate.ps1
@@ -23,7 +23,7 @@ param(
[int]$BuildTimeoutSeconds = 900,
[int]$TestTimeoutSeconds = 600,
[int]$HangTimeoutSeconds = 180,
- [string]$TestFilter = 'Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Purpose!=Diagnostic&Status!=KnownFailure',
+ [string]$TestFilter = 'Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Lane!=Windows&Lane!=Linux&Lane!=SystemFont&Purpose!=Diagnostic&Status!=KnownFailure',
[switch]$SkipRestore,
[switch]$SkipBuild
)