using System.Linq; using System.Numerics; using AcDream.App.Rendering; using AcDream.App.Rendering.Gpu; using AcDream.App.Rendering.Walk; using DatReaderWriter; namespace AcDream.App.Tests.Rendering.Walk; /// /// S4-c1 fix round 1, F3: the automated depth-event transcript gate. /// Replays each OH alpha/depth capture's frame 2 through the SAME ported /// walk ( + , /// + /// — the identical replay harness /// already uses) with a RECORDING sink/leaf pair that reproduces retail's /// own PM (mode, counterBefore) and PC (ov, counter, forceClear) sequences, /// then compares them against 's parse of /// the real capture, exactly (pointers ignored). /// /// Why two observation points, not one. Retail's PM line fires /// at DrawPortalPolyInternal's function ENTRY — before the four-plane /// boundary guard (S4-c1 F1) has run — so a PM line is emitted for every /// ATTEMPT, guard-rejected or not. A building punch's guard decision runs /// INSIDE (a Collect-time /// hook): a rejected punch never reaches /// at all, so intercepts /// OnPunchGeometry ITSELF, at Collect time, before the guard runs — /// reading there gives the /// PRE-reset value retail's own punches observe (Collect completes entirely /// before Replay starts, so reading the counter at Replay time would already /// see the root's own post-reset value — the wrong number, confirmed against /// holtburg-doorway-still's own counterBefore=0002 punches immediately /// followed by counterBefore=0000/0001 seals in the SAME turn). Exit seals /// have no such Collect-time per-portal hook at all ( takes no cell/portal /// argument — RetailPViewPassExecutor.DrawPortalDepthWrite owns the /// real per-portal loop entirely at Replay time), so /// reproduces that SAME loop (S4-c1 F1's guard, F2's count-before-clip order) /// directly over the walk's own /// / / — /// the identical LOCAL portal-polygon data the production seal path reads, /// at Replay time, which is also where retail's own exit-seal loop runs /// (established: punches always precede the single per-root ExitSeals /// Collect-time event, so simple list concatenation reproduces the exact /// interleaved PM order without needing a shared Collect/Replay timeline). /// /// /// Why the counter is SEEDED, not primed by a throwaway pass /// (S4-c1 fix round 2, R2-2). Retail's portalsDrawnCount is a /// PERSISTENT session global (wo(008719b4)), unaffected by any reset /// between captured frames — a running client carries whatever value the /// counter last settled at into every subsequent capture. Each fixture's /// own FIRST PM or PC line (wherever it falls — including the "F 1" /// preamble text a cdb session prints before the first parsed frame /// marker, which is where terrace-edge's and holtburg-doorway-still's own /// first samples live) already carries that pre-capture value: /// cathedral-arrival 0, cathedral-leak 0, foundry-deep 1, /// holtburg-doorway-still 2, terrace-edge 2, cathedral-stair-arch 8 (see /// 's own doc comment). /// Fix round 1 tried to reach a matching steady state by running a /// throwaway "priming" Collect+Replay pass first and discarding its /// output — this works only for a fixture whose captured frames themselves /// contain enough seal activity to climb from a cold /// PortalsDrawnCount=0 start up to the needed value (holtburg- /// doorway-still, foundry-deep); terrace-edge's own capture never runs a /// qualifying interior turn at all (every PC line reads ov=0), so no /// number of priming passes from a cold start can ever reach its /// counterBefore=2 — the value has to come from BEFORE the capture, /// not from replaying the capture against itself. Seeding /// directly from the /// fixture's own first sample before a SINGLE Collect+Replay pass fixes /// this for every pose, terrace-edge included, without changing what a /// pose with real seal activity computes (a fixture's own first sample /// IS the steady-state value fix round 1's priming pass converged to, /// since a steady state is by definition unchanged by one more pass). /// public sealed partial class WalkTraceConformanceTests { /// Collect-time decorator: forwards /// every hook to the real unchanged (so its /// own event collection stays complete and correct), while separately /// recording the two families this gate needs — see this file's own /// class doc comment for why punches must be captured HERE rather than /// at Replay. private sealed class AlphaDepthCollectSink : IWalkEventSink { private readonly WalkFrameDriver _driver; private readonly IWalkEventSink _inner; public AlphaDepthCollectSink(WalkFrameDriver driver) { _driver = driver; _inner = driver; } public readonly List<(int Mode, int CounterBefore)> Punches = new(); public readonly List<(int Ov, int Counter, int ForceClear)> PcEvents = new(); public void Emit(in WalkEvent walkEvent) { // PView::DrawCells @0x005a4840's own PC print fires at function // ENTRY for every call — the root's own turn AND every building // look-in's re-entrant call alike (oh1-depth-lifecycle.md: the // breakpoint doesn't distinguish). WalkEventKind.DrawCells's // Emit call is the walk's own "this DrawCells call happened" // signal at that SAME entry-order point (its own doc comment: // "sits at breakpoint-ENTRY order"); forceClear (oh1: no write // site found anywhere in the binary) is always 0. if (walkEvent.Kind == WalkEventKind.DrawCells) PcEvents.Add((walkEvent.OutsideViewCount, _driver.PortalsDrawnCount, 0)); _inner.Emit(walkEvent); } public void OnLandscapeViews(WalkPortalView activeViews) => _inner.OnLandscapeViews(activeViews); public void OnLandCellTurn(uint landblockId, int sideCellCount, int cellIndex) => _inner.OnLandCellTurn(landblockId, sideCellCount, cellIndex); public void OnSortCellTurn(uint landblockId, int sideCellCount, int cellIndex) => _inner.OnSortCellTurn(landblockId, sideCellCount, cellIndex); public void OnLandscapeCellTurn(uint cellId) => _inner.OnLandscapeCellTurn(cellId); public void OnLandscapeCellTurn(uint landblockId, int sideCellCount, int cellIndex) => _inner.OnLandscapeCellTurn(landblockId, sideCellCount, cellIndex); public void OnBuildingTurn(WalkBuilding building) => _inner.OnBuildingTurn(building); public void OnBuildingShellTurn( WalkBuilding building, WalkBuildingSelection selection) => _inner.OnBuildingShellTurn(building, selection); public void OnPunchGeometry( WalkBuilding building, WalkPolygon polygon, int activeViewIndex) { // Far-Z punches never touch portalsDrawnCount (R2); this reads // it purely as a snapshot for the transcript, BEFORE the SAME // interior root's own OnInteriorFloodDrawTurn reset — see class // doc comment. Punches.Add((1, _driver.PortalsDrawnCount)); _inner.OnPunchGeometry(building, polygon, activeViewIndex); } public void OnInteriorFloodDrawTurn(IReadOnlyList cells, int outsideViewCount) => _inner.OnInteriorFloodDrawTurn(cells, outsideViewCount); public void OnWeatherTurn(uint viewerCellId) => _inner.OnWeatherTurn(viewerCellId); } /// Replay-time : every /// member besides is a plain no-op (this /// gate cares only about the depth/count mechanism, not mesh content). /// reproduces /// RetailPViewPassExecutor.DrawPortalDepthWrite's real per-portal /// loop — S4-c1 F1's guard, F2's count-before-clip order — directly over /// the walk's own flood/cell data (no fake GPU clip needed: F2 /// established the count happens unconditionally once the guard /// passes). private sealed class AlphaDepthLeaf : IWalkFrameLeafRenderer { private readonly Dictionary _cells; /// S4-c2 gate G-c2: the real production queue — this gate's /// walk carries no live GfxObj/particle mesh content (same design as /// this file's own PM/PC harness: /// returns empty everywhere), so stays at /// ClipCount/AlphaCount == 0 throughout — but the SEQUENCE of (site, /// threshold) calls the walk drives it through, and each call's /// real no-op-vs-drain decision under those (always-empty) counts, /// are both genuine production behavior, not stubbed. private readonly RetailAlphaQueue _queue; public AlphaDepthLeaf(Dictionary cells, RetailAlphaQueue queue) { _cells = cells; _queue = queue; } /// Set once, immediately after construction — the leaf and /// its owning are mutually referential /// (the driver's constructor requires the leaf), so this cannot be a /// constructor parameter. public WalkFrameDriver Driver { get; set; } = null!; public readonly List<(int Mode, int CounterBefore)> Seals = new(); /// Every ACTUAL flush this replay drove the queue through, /// in order — (site, threshold, clip count observed immediately /// BEFORE the drain, alpha count observed immediately BEFORE the /// drain). A no-op call (both counts stay strictly under /// threshold*3000) is not recorded, matching /// 's /// own definition of "a flush" on the capture side. public readonly List<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> ActualFlushes = new(); private void RecordFlush(RetailAlphaFlushSite site, float threshold) { int clipBefore = _queue.ClipCount; int alphaBefore = _queue.AlphaCount; // Same no-op predicate as D3DPolyRender::FlushAlphaList itself // (RetailAlphaQueue.Flush) — computed here, before the real // call, purely so this recorder can decide whether THIS call // counts as "a flush" for the transcript. bool noOp = clipBefore < threshold * RetailAlphaQueue.ListCapacity && alphaBefore < threshold * RetailAlphaQueue.ListCapacity; _queue.Flush(site, threshold); if (!noOp) ActualFlushes.Add((site, threshold, clipBefore, alphaBefore)); } public void DrawSky() { } public void DrawLandCellBatch( IReadOnlyList<(uint LandblockId, int SideCellCount, int CellIndex)> cells) { } public bool HasRenderableEmittersInCell(uint cellId) => false; public void DrawCellShell(uint cellId) { } public ReadOnlySpan PrepareStaticParticles(uint cellId) => ReadOnlySpan.Empty; public ReadOnlySpan PrepareCellParticles(uint cellId) => ReadOnlySpan.Empty; public void ClearInteriorDepth() { } public void FlushLandscape() => RecordFlush(RetailAlphaFlushSite.LandscapeFlush, 0f); public void DrawPunchFan(WalkPolygon worldPolygon, int activeViewIndex) { } public void AlphaBarrier() => RecordFlush(RetailAlphaFlushSite.DrawBuilding, 0f); public void FlushSortCellExit() => RecordFlush(RetailAlphaFlushSite.SortCellExit, 0.75f); public int DrawExitSeals() { int accepted = 0; List flood = Driver.InteriorFloodCells; // Reverse order — the SAME direction DrawWalkExitPortalMasks // walks driver.InteriorFloodCells in production // (RetailPViewRenderer.cs). for (int i = flood.Count - 1; i >= 0; i--) { if (!_cells.TryGetValue(flood[i], out WalkCell? cell)) continue; int sliceCount = Driver.InteriorFloodViewSliceCountAt(i); for (int slice = 0; slice < sliceCount; slice++) { for (int p = 0; p < cell.Portals.Length; p++) { WalkCellPortal portal = cell.Portals[p]; // Walk-side exit sentinel is 32-bit 0xFFFFFFFF // (WalkCellPortal's own doc comment) — the render- // side CellPortalInfo's 16-bit 0xFFFF is a DIFFERENT // representation of the same fact. if (portal.OtherCellId != 0xFFFFFFFFu) continue; if ((uint)portal.PolygonIndex >= (uint)cell.PortalPolygons.Length) continue; WalkPolygon poly = cell.PortalPolygons[portal.PolygonIndex]; // F2: count happens BEFORE clip (unconditionally, // once the guard passes) — counterBefore is the // running total BEFORE this specific portal's own // decision. Seals.Add((0, Driver.PortalsDrawnCount + accepted)); if (!WalkVisibilityMath.IsRejectedByPortalPolygonBoundaryGuard( poly.Vertices)) { accepted++; } } } } return accepted; } } /// Minimal : this gate never /// inspects mesh content, only the depth/count event sequence, so every /// query returns the shared empty record. private sealed class EmptyAlphaDepthWorldData : IWalkFrameWorldData { public WalkFrameStaticRecords GetCellObjects(uint cellId) => WalkFrameStaticRecords.Empty; public WalkFrameStaticRecords GetOutdoorObjects(uint cellId) => WalkFrameStaticRecords.Empty; public WalkFrameStaticRecords GetCellStatics(uint cellId) => WalkFrameStaticRecords.Empty; public WalkFrameStaticRecords GetCellDynamics(uint cellId) => WalkFrameStaticRecords.Empty; public WalkFrameStaticRecords GetOutdoorStatics(uint cellId) => WalkFrameStaticRecords.Empty; public WalkFrameStaticRecords GetOutdoorDynamics(uint cellId) => WalkFrameStaticRecords.Empty; public WalkFrameStaticRecords GetBuildingShellStatics(WalkBuilding building) => WalkFrameStaticRecords.Empty; public Matrix4x4 GetBuildingWorldTransform(WalkBuilding building) => Matrix4x4.Identity; } /// Seeds from /// 's own first observed sample (S4-c1 fix /// round 2, R2-2 — see class doc comment), runs ONE Collect+Replay pass, /// and asserts BOTH the PM and PC sequences against /// 's captured frame 2 /// ('s frames[1], matching every /// other OH-capture row's own frame-2 convention in this file). /// R2-1 (gate honesty): both diffs are computed BEFORE either is /// asserted, so a PM mismatch can never prevent the PC comparison from /// running (or vice versa) — a written claim that one sequence /// "matches" is only ever one this method actually evaluated. /// private void RunAlphaDepthTranscriptGate(string fixtureName) { IReadOnlyList poseFrames = WalkOracleTrace.Load(OhCaptureRoot, fixtureName); Assert.NotEmpty(poseFrames); Assert.True(poseFrames.Count > 1, $"{fixtureName}: need a captured frame 2."); WalkOracleFrame poseFrame = poseFrames[1]; Assert.NotNull(poseFrame.Pose); WalkOraclePose pose = poseFrame.Pose!; IReadOnlyList depthFrames = WalkAlphaDepthTrace.Load(OhCaptureRoot, fixtureName); Assert.True(depthFrames.Count > 1, $"{fixtureName}: need a captured frame 2's PM/PC content."); WalkAlphaDepthFrame expected = depthFrames[1]; int initialCounter = WalkAlphaDepthTrace.LoadInitialCounter(OhCaptureRoot, fixtureName); using DatCollection dats = OpenDats(); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, pose.CellId, pose.Origin); var ctx = new WalkTraceReplayContext(pose, world.Cells) { Buildings = world.Buildings }; WalkCell? camera = (pose.CellId & 0xFFFFu) >= 0x100 ? Assert.Contains(pose.CellId, world.Cells) : null; using var fx = new WalkFrameDriverTests.DispatcherFixture(); var worldData = new EmptyAlphaDepthWorldData(); // S4-c2: AlphaDepthLeaf now records every flush through a real // RetailAlphaQueue (used by the AM/FL sibling gate below); this PM/PC // gate doesn't care about that queue's transcript, but it still must // be a valid ACTIVE frame or AlphaBarrier/FlushLandscape/ // FlushSortCellExit's real Flush() calls throw. var alphaQueue = new RetailAlphaQueue(); var leaf = new AlphaDepthLeaf(world.Cells, alphaQueue); var driver = new WalkFrameDriver(fx.Dispatcher, leaf, worldData); leaf.Driver = driver; var sink = new AlphaDepthCollectSink(driver); var walk = new RetailFrameWalk(100f, 0.99f); // R2-2: seed the persistent counter from the fixture's own // pre-capture value instead of priming a throwaway first pass. driver.PortalsDrawnCount = initialCounter; alphaQueue.BeginFrame(); using (WalkFrameDriverTests.DrawScope draw = fx.BeginDraw()) { driver.BeginFrame(ctx, Matrix4x4.Identity, pose.Origin); walk.WalkFrame(pose.CellId, camera, world.Landscape, ctx, sink); driver.EndFrame(); driver.Replay(draw.Frame, draw.Pass); } // DrawScope.Dispose ends only the pass/publication — the frame // itself (RecordingGpuDevice's "one open frame" invariant) is // ended separately, same order WalkOutsideViewReassemblyTests' // own multi-draw loop uses. fx.FrameLifetime.EndFrame(); alphaQueue.EndFrame(); var actualPm = new List<(int Mode, int CounterBefore)>(sink.Punches); actualPm.AddRange(leaf.Seals); IReadOnlyList<(int Ov, int Counter, int ForceClear)> actualPc = sink.PcEvents; bool pmMatches = expected.PmEvents.SequenceEqual(actualPm); bool pcMatches = expected.PcEvents.SequenceEqual(actualPc); if (!pmMatches || !pcMatches) { Assert.Fail( $"{fixtureName}: PM {(pmMatches ? "matches" : "DIVERGES")} " + $"— expected {FormatPm(expected.PmEvents)}, actual {FormatPm(actualPm)}; " + $"PC {(pcMatches ? "matches" : "DIVERGES")} " + $"— expected {FormatPc(expected.PcEvents)}, actual {FormatPc(actualPc)}"); } } /// /// S4-c2 gate G-c2, split by S4-c2 fix round 1 (M5): extends this file's /// own PM/PC transcript gate from depth events to the AM/FL alpha-queue /// stream. Reuses the EXACT SAME replay harness /// (: no live GfxObj/particle mesh /// content, matching this file's own established PM/PC pattern) with a /// real wired through /// 's flush hooks. Returns BOTH the expected /// and actual transcripts so and /// can assert their own dimension /// over the SAME replay logic without duplicating the harness setup. /// private static ( IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> Expected, IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> Actual) RunAlphaFlushTranscriptReplay(string fixtureName) { IReadOnlyList poseFrames = WalkOracleTrace.Load(OhCaptureRoot, fixtureName); Assert.NotEmpty(poseFrames); Assert.True(poseFrames.Count > 1, $"{fixtureName}: need a captured frame 2."); WalkOracleFrame poseFrame = poseFrames[1]; Assert.NotNull(poseFrame.Pose); WalkOraclePose pose = poseFrame.Pose!; IReadOnlyList depthFrames = WalkAlphaDepthTrace.Load(OhCaptureRoot, fixtureName); Assert.True(depthFrames.Count > 1, $"{fixtureName}: need a captured frame 2's AM/FL content."); WalkAlphaDepthFrame expectedFrame = depthFrames[1]; int initialCounter = WalkAlphaDepthTrace.LoadInitialCounter(OhCaptureRoot, fixtureName); var expected = WalkAlphaDepthTrace.BuildExpectedFlushTranscript(expectedFrame); using DatCollection dats = OpenDats(); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, pose.CellId, pose.Origin); var ctx = new WalkTraceReplayContext(pose, world.Cells) { Buildings = world.Buildings }; WalkCell? camera = (pose.CellId & 0xFFFFu) >= 0x100 ? Assert.Contains(pose.CellId, world.Cells) : null; using var fx = new WalkFrameDriverTests.DispatcherFixture(); var worldData = new EmptyAlphaDepthWorldData(); var queue = new RetailAlphaQueue(); var leaf = new AlphaDepthLeaf(world.Cells, queue); var driver = new WalkFrameDriver(fx.Dispatcher, leaf, worldData); leaf.Driver = driver; var sink = new AlphaDepthCollectSink(driver); var walk = new RetailFrameWalk(100f, 0.99f); driver.PortalsDrawnCount = initialCounter; queue.BeginFrame(); using (WalkFrameDriverTests.DrawScope draw = fx.BeginDraw()) { driver.BeginFrame(ctx, Matrix4x4.Identity, pose.Origin); walk.WalkFrame(pose.CellId, camera, world.Landscape, ctx, sink); driver.EndFrame(); driver.Replay(draw.Frame, draw.Pass); } fx.FrameLifetime.EndFrame(); // SmartBox::RenderNormalMode's own top-level FlushAlphaList(0f) — // RetailAlphaQueue.EndFrame() calls this internally, so it is // recorded here rather than through a leaf hook (see // RetailAlphaQueue.EndFrame's own doc comment). int clipBeforeFinal = queue.ClipCount; int alphaBeforeFinal = queue.AlphaCount; queue.EndFrame(); leaf.ActualFlushes.Add( (RetailAlphaFlushSite.RenderNormalMode, 0f, clipBeforeFinal, alphaBeforeFinal)); return (expected, leaf.ActualFlushes); } /// /// S4-c2 fix round 1 (M5): the LIVE half of gate G-c2 — the SEQUENCE of /// (site, threshold) the walk drives the queue through (which of the /// four normal-world sites fires, how many times, in what order) is /// purely structural (a function of cell/building/land-cell traversal, /// never of mesh content), so it is a real, unconditional pass/fail with /// no KnownFailure tag — a future site-sequence regression is now /// visible in the hermetic/InstalledDat lanes instead of being buried /// under the (expected-red) count dimension. /// private void RunAlphaFlushSitesGate(string fixtureName) { ( IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> expected, IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> actual ) = RunAlphaFlushTranscriptReplay(fixtureName); bool siteSequenceMatches = expected .Select(e => (e.Site, e.Threshold)) .SequenceEqual(actual.Select(a => (a.Site, a.Threshold))); Assert.True( siteSequenceMatches, $"{fixtureName}: flush SITE sequence diverges (content-independent — this must " + $"match unconditionally) — expected {FormatFlushSites(expected)}, " + $"actual {FormatFlushSites(actual)}"); } /// /// S4-c2 fix round 1 (M5): the KnownFailure half of gate G-c2 — the /// drained entry count PER LIST can never match by construction, for /// THREE independent reasons (not just "harness content only", the /// prior write-up's incomplete claim): (1) this harness carries no live /// GfxObj/particle mesh content at all (), /// so every 0f-threshold flush observes count (0, 0) — always a real /// drain (0 is never < 0), matching retail's own always-drains /// behavior at threshold 0f, but with a different count than the /// capture's real content volume; (2) AP-238 coalesces transparent /// EnvCell work to one token per (cell,list), whereas retail /// appends each contributing subset; (3) AP-239/AP-240 change /// CLIP-vs-ALPHA membership for the named ordinary-Wb surface cases. /// Ordinary Wb and particle paths otherwise append per real subset; the /// former broad "per instance versus per subset" explanation was false. /// See the S4 packet's §9/§10/§11 subsections for the full per-pose /// sequences. /// private void RunAlphaFlushCountsGate(string fixtureName) { ( IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> expected, IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> actual ) = RunAlphaFlushTranscriptReplay(fixtureName); // Recorded as a real, evaluated assertion (never weakened), expected // to diverge on the count dimension for any pose with real content — // callers gate on Status=KnownFailure, not on this passing. bool fullMatches = expected.SequenceEqual(actual); Assert.True( fullMatches, $"{fixtureName}: flush transcript diverges on drained COUNT only (the site+threshold " + "sequence is separately verified exact by AlphaFlushSites_*) — see this method's " + $"own doc comment for the three reasons this can never match — expected " + $"{FormatFlushCounts(expected)}, actual {FormatFlushCounts(actual)}"); } private static string FormatFlushSites( IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> events) => "[" + string.Join(", ", events.Select(e => $"({e.Site},thresh={e.Threshold})")) + "]"; private static string FormatFlushCounts( IReadOnlyList<(RetailAlphaFlushSite Site, float Threshold, int DrainedClip, int DrainedAlpha)> events) => "[" + string.Join( ", ", events.Select(e => $"({e.Site},thresh={e.Threshold},clip={e.DrainedClip},alpha={e.DrainedAlpha})")) + "]"; /// S4-c2 fix round 1 (M5): the live half — see /// 's own doc comment. No /// KnownFailure tag: this dimension is content-independent and must /// match unconditionally. [Fact] public void AlphaFlushSites_CathedralArrival_MatchesRetailFrame2() => RunAlphaFlushSitesGate("cathedral-arrival.alphadepth"); /// S4-c2 fix round 1 (M5): the KnownFailure half — see /// 's own doc comment for the three /// independent reasons the drained COUNT can never match by /// construction. [Fact] [Trait("Status", "KnownFailure")] public void AlphaFlushCounts_CathedralArrival_MatchesRetailFrame2() => RunAlphaFlushCountsGate("cathedral-arrival.alphadepth"); [Fact] public void AlphaFlushSites_CathedralLeak_MatchesRetailFrame2() => RunAlphaFlushSitesGate("cathedral-leak.alphadepth"); [Fact] [Trait("Status", "KnownFailure")] public void AlphaFlushCounts_CathedralLeak_MatchesRetailFrame2() => RunAlphaFlushCountsGate("cathedral-leak.alphadepth"); [Fact] public void AlphaFlushSites_CathedralStairArch_MatchesRetailFrame2() => RunAlphaFlushSitesGate("cathedral-stair-arch.alphadepth"); [Fact] [Trait("Status", "KnownFailure")] public void AlphaFlushCounts_CathedralStairArch_MatchesRetailFrame2() => RunAlphaFlushCountsGate("cathedral-stair-arch.alphadepth"); [Fact] public void AlphaFlushSites_FoundryDeep_MatchesRetailFrame2() => RunAlphaFlushSitesGate("foundry-deep.alphadepth"); [Fact] [Trait("Status", "KnownFailure")] public void AlphaFlushCounts_FoundryDeep_MatchesRetailFrame2() => RunAlphaFlushCountsGate("foundry-deep.alphadepth"); [Fact] public void AlphaFlushSites_HoltburgDoorwayStill_MatchesRetailFrame2() => RunAlphaFlushSitesGate("holtburg-doorway-still.alphadepth"); [Fact] [Trait("Status", "KnownFailure")] public void AlphaFlushCounts_HoltburgDoorwayStill_MatchesRetailFrame2() => RunAlphaFlushCountsGate("holtburg-doorway-still.alphadepth"); [Fact] public void AlphaFlushSites_TerraceEdge_MatchesRetailFrame2() => RunAlphaFlushSitesGate("terrace-edge.alphadepth"); [Fact] [Trait("Status", "KnownFailure")] public void AlphaFlushCounts_TerraceEdge_MatchesRetailFrame2() => RunAlphaFlushCountsGate("terrace-edge.alphadepth"); private static string FormatPm(IReadOnlyList<(int Mode, int CounterBefore)> events) => "[" + string.Join(", ", events.Select(e => $"(mode={e.Mode},counterBefore={e.CounterBefore})")) + "]"; private static string FormatPc(IReadOnlyList<(int Ov, int Counter, int ForceClear)> events) => "[" + string.Join(", ", events.Select(e => $"(ov={e.Ov},counter={e.Counter},fc={e.ForceClear})")) + "]"; [Fact] public void AlphaDepthTranscript_CathedralArrival_MatchesRetailFrame2() => RunAlphaDepthTranscriptGate("cathedral-arrival.alphadepth"); [Fact] public void AlphaDepthTranscript_FoundryDeep_MatchesRetailFrame2() => RunAlphaDepthTranscriptGate("foundry-deep.alphadepth"); [Fact] public void AlphaDepthTranscript_HoltburgDoorwayStill_MatchesRetailFrame2() => RunAlphaDepthTranscriptGate("holtburg-doorway-still.alphadepth"); /// /// S4-c1 fix round 2 (R2-2): seeding /// from terrace-edge's own first observed sample (counterBefore=2, /// carried in the file's pre-"F 1" preamble text — see /// 's own doc /// comment) closes fix round 1's KnownFailure. Under a cold 0 /// BOTH sequences diverged in the counter field — PM expected /// (1,2),(1,2) and PC expected (0,2,0),(0,2,0) against a /// cold (1,0)/(0,0,0) — round 1's write-up wrongly called /// the PC side a match, and round 2's gate-honesty lens caught the same /// sentence re-worded here (lead correction at landing). Seeded, both /// sequences match exactly; this pose never runs a qualifying interior /// turn, so PC stays ov=0 with the seeded counter. /// [Fact] public void AlphaDepthTranscript_TerraceEdge_MatchesRetailFrame2() => RunAlphaDepthTranscriptGate("terrace-edge.alphadepth"); /// /// S4-c1 fix round 2, R2-4: the sixth pose (#464 artifact pose, root /// 0xF4180114, seven outside views). Sixteen building punches — /// all mode=1, all counterBefore=0008 (far-Z punches never /// touch the counter) — then eight true-depth exit seals with /// counterBefore running 0..7 against the root's own /// ov=7 read-then-zero. This gate compares only the /// (mode, counterBefore) and (ov, counter, forceClear) /// tuples: it does NOT observe which of the sixteen punches the ±12 /// boundary guard rejects (the sink records every attempt before the /// guard runs; the pmverts capture and the DAT, not this Fact, /// show twelve of them lying on local y=12.000 — S4 packet §9). /// The seed 8 is the first PM/PC sample /// finds in the /// file, which for this fixture lies inside frame 1 (this capture has no /// pre-"F 1" preamble sample); with the priming pass gone, frame 2's PC /// counter equals that seed by construction in steady state. /// [Fact] public void AlphaDepthTranscript_CathedralStairArch_MatchesRetailFrame2() => RunAlphaDepthTranscriptGate("cathedral-stair-arch.alphadepth"); /// Cathedral-leak carries the exact same steady state (counter /// pinned at 0, every exit portal degenerate-onto-plane rejected) as /// cathedral-arrival; listed here (S4-c1 fix round 1, F3) because the /// original spec's own fixture count (four) undercounts the five /// *.alphadepth.log files that were already present in /// oh-capture/ at that round — see that round's commit body. [Fact] public void AlphaDepthTranscript_CathedralLeak_MatchesRetailFrame2() => RunAlphaDepthTranscriptGate("cathedral-leak.alphadepth"); }