using AcDream.App.Tests.Rendering; using AcDream.App.Rendering.Walk; using DatReaderWriter; using DatReaderWriter.Options; namespace AcDream.App.Tests.Rendering.Walk; /// /// FW1's conformance gate, first slice: replay pose-stamped oracle /// fixtures through the ported walk and require the identical event /// sequence. The projection-light interior fixtures gate first /// (docs/research/2026-08-30-fw-walk-oracle/README.md, posed round); /// the outdoor/landscape fixtures join as the landscape world build /// lands. /// [Trait("Lane", "InstalledDat")] public sealed partial class WalkTraceConformanceTests { /// S3 chunk 1 fix round 1 (G10): besides the plain /// list the four-kind /// /// still uses, also builds the full eight-kind token stream — LS/BLD/ /// DI/DC/LC/SC/EC/OC — AS each hook fires, for /// . /// mirrors WalkFrameDriver's own private /// _currentDcStage: null until the frame's first /// (the interior root's own /// flood defers its EC/OC to ), /// flips true forever once a building's portal pass begins /// () — see /// 's own doc /// comment for why this never resets mid-frame. S3 chunk 1 fix round 2 /// (§11.6 H3): this REPLAY-side derivation is unchanged — only the /// ORACLE side () /// moved off derivation onto its own literal captured EC/OC lines. /// /// KNOWN LIMIT (S3 review fix round 1, F4a): the production /// transcript prints EC once per LIVE VIEW of a flood cell /// (retail's setup_view/DrawEnvCell loop, /// PView::DrawCells @0x005a4ab1–0x005a4acc), but this replay /// side's still /// derives ONE EC per cell — the sink event carries no per-cell /// view count. Every fixture passes only because no captured flood cell /// holds more than one live view at DrawCells time. A fixture with a /// two-view flood cell would fail here on the second EC; S5's /// transcript closeout carries the per-cell view count through the /// sink event and removes this note. private sealed class Recorder : IWalkEventSink { public readonly List Events = new(); public readonly List Tokens = new(); private bool? _lookIn; public void Emit(in WalkEvent walkEvent) { Events.Add(walkEvent); switch (walkEvent.Kind) { case WalkEventKind.Landscape: Tokens.Add("LS"); break; case WalkEventKind.Building: Tokens.Add($"BLD:{walkEvent.CellId:x8}"); break; case WalkEventKind.DrawInside: Tokens.Add($"DI:{walkEvent.CellId:x8}"); _lookIn = false; break; case WalkEventKind.DrawCells: Tokens.Add( $"DC:ov={walkEvent.OutsideViewCount}:" + string.Join(',', walkEvent.Cells.Select(c => c.ToString("x8")))); // A look-in flood's DC draws its EC/OC immediately // (RetailFrameWalk.HandleDrawCellsTurn calls // EmitFloodTurns right here for WalkDrawStage. // LookInStatic); the interior root's OWN flood (stage // CellStatic, _lookIn still false) defers to // OnInteriorFloodDrawTurn below — see that method. if (_lookIn == true) WalkTraceReplayContext.AppendFloodTurns(Tokens, walkEvent.Cells); break; } } public void OnLandCellTurn(uint landblockId, int sideCellCount, int cellIndex) => Tokens.Add( $"LC:{WalkTranscriptDump.LodCellId(landblockId, sideCellCount, cellIndex):x8}"); public void OnSortCellTurn(uint landblockId, int sideCellCount, int cellIndex) => Tokens.Add( $"SC:{WalkTranscriptDump.LodCellId(landblockId, sideCellCount, cellIndex):x8}"); public void OnBuildingTurn(WalkBuilding building) => _lookIn = true; public void OnInteriorFloodDrawTurn(IReadOnlyList cells, int outsideViewCount) => WalkTraceReplayContext.AppendFloodTurns(Tokens, cells); /// S3 review fix round 1 (F4b): retail's trailing per-frame /// weather turn (GameSky::Draw(sky,1) @0x00506ff0, fired by /// RetailFrameWalk.DrawLandscape when ctx.WeatherGateOpen /// holds) prints its own "OC" line /// (WalkFrameDriver.OnWeatherTurn's production sibling) — /// before this fix the interface's default no-op left the replay /// side of the eight-kind signature silently blind to it, so /// /// had to drop the SAME line from the oracle side just to keep both /// sides comparable (a pin that could never fail on the weather /// turn's own placement/value). Recording it here the SAME way /// records every other "OC" (identical token /// shape) lets the oracle side compare literally instead. public void OnWeatherTurn(uint viewerCellId) => Tokens.Add($"OC:{viewerCellId:x8}"); } private static DatCollection OpenDats() { string? datDir = CornerFloodReplayTests.ResolveDatDir(); if (datDir is null) { Assert.Fail("Lane=InstalledDat requires an installed retail DAT directory; see docs/release-gate.md."); } return new DatCollection(datDir!, DatAccessType.Read); } [Fact] public void Street_outdoor_first_frame_diff() { // The first landscape-involving conformance case: diff-first (the // assert prints both signatures on mismatch for adjudication). IReadOnlyList frames = WalkOracleTrace.Load("posed/holtburg-street-outdoor"); Assert.NotEmpty(frames); using DatCollection dats = OpenDats(); WalkOracleFrame frame = frames[1]; // frame 2: pose settled (marker timing) Assert.NotNull(frame.Pose); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, frame.Pose!.CellId, frame.Pose.Origin); var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells) { Buildings = world.Buildings, }; var walk = new RetailFrameWalk(100f, 0.99f); var recorder = new Recorder(); walk.WalkFrame(frame.Pose.CellId, null, world.Landscape, ctx, recorder); string expected = WalkTraceReplayContext.Signature(frame); string actual = WalkTraceReplayContext.Signature(recorder.Events); Assert.True( expected == actual, $"walk diverged from retail\nEXPECTED: {expected}\nACTUAL: {actual}"); } [Fact] public void Doorway_still_first_frame_diff() { // Interior flood adjudication: DI + DC(ov=2, n=3) + the landscape // through two exit views — tests the flood depth in isolation from // the building look-in machinery. IReadOnlyList frames = WalkOracleTrace.Load("posed/holtburg-doorway-still"); Assert.NotEmpty(frames); using DatCollection dats = OpenDats(); WalkOracleFrame frame = frames[1]; Assert.NotNull(frame.Pose); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, frame.Pose!.CellId, frame.Pose.Origin); var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells) { Buildings = world.Buildings, }; WalkCell camera = Assert.Contains(frame.Pose.CellId, world.Cells); // Render::deg_mul is DYNAMIC (auto-tuned by frame load), and this // capture ran right after the heavy terrace-edge capture with the // multiplier depressed: at mul ≤ 0 the degrade thresholds sit at or // below each level's ideal, so 001e (eff 29.3), 0026 (27.1), and // 002f (43.4) all select the portless level 1 — retail's zero // look-in floods. Every other fixture pins ≈ +0.99 (thresholds at // max). The recon session's live dump read −0.99 under the same cdb // load. Re-dump deg_mul per capture at the next retail session. var walk = new RetailFrameWalk(100f, 0f); var recorder = new Recorder(); walk.WalkFrame(frame.Pose.CellId, camera, world.Landscape, ctx, recorder); string expected = WalkTraceReplayContext.Signature(frame); string actual = WalkTraceReplayContext.Signature(recorder.Events); Assert.True( expected == actual, $"walk diverged from retail\nEXPECTED: {expected}\nACTUAL: {actual}"); } /// /// PINNED RED 2026-09-03 (S3 chunk 1 fix round 1, G10 — un-skip with the /// fix): the eight-kind signature is the FIRST comparison ever run at /// LC/SC placement/content against a DAT-built world for this fixture /// (the old four-kind Signature filtered LC/SC out entirely — how the /// G7 SC-ordering regression shipped green). One real divergence /// survives after fixing the LandblockId=0 fixture bug this same round /// uncovered (WalkLandscapeDatBuilder.cs — a genuinely separate, /// already-fixed defect): at token index 165, the replay draws ONE /// EXTRA land-cell pair retail never does — /// …SC:a8c90001|LC:a8c90001|SC:a8c90001| retail jumps straight to /// LC:95c60001; the replay inserts LC:a9c90001|SC:a9c90001 /// first. A single spurious block admission at a ring-2/ring-3 LOD /// boundary near this pose — a real WalkLandscape.CheckBlocks /// visibility question, not a print-site or ordering bug, and out of /// this round's print-only scope (§11.4) — needs the retail oracle /// (decomp/cdb) to resolve. Filed as docs/ISSUES.md #458. /// terrace-edge/cathedral-arrival/foundry-deep all reproduce EXACTLY at /// this same eight-kind level; only this row's specific pose hits the /// boundary. S3 chunk 1 fix round 2 (§11.6 H3) switched the ORACLE side /// of the eight-kind signature from a derived EC/OC to retail's own /// LITERAL captured EC/OC lines — re-verified 2026-09-03 that this /// divergence stays at the SAME token index 165 (an LC/SC-only mismatch, /// upstream of any EC/OC content) under the new comparison; #458's /// position is unchanged. /// /// RESOLVED 2026-09-03 (lead, two live cdb captures — see /// docs/ISSUES.md #458 and register row AD-118): it is a PRECISION /// BOUNDARY, not a structural walk divergence. At this fixture pose the /// replay's block test for a9c9 (ring 21 north, z slab 75..330) /// has three of the four block corners OUTSIDE the doorway's fourth /// edge plane and the south-west corner just INSIDE it, so /// block_plane_check says PartiallyInside and the block draws; /// retail's plane sits about 0.5% away (measured at a nearby pose: /// retail's clip heights 300.4/310.2 m vs the replay's 298.8/308.5 m /// for the same block, with the SAME sentinel pattern and the SAME /// verdicts 1 then 0 in the two views) and puts that last corner /// outside too. The row stays KnownFailure on purpose: the fixture is /// retail's literal frame, and no bit-exact fix exists short of /// reproducing D3D's x87 projection. /// [Fact] [Trait("Status", "KnownFailure")] public void Oh_doorway_still_first_frame_diff() { // S3 chunk 1 (§11.2 B3): the OH kit pose's own doorway-still capture // — DI a9b4013f, DC(ov=2, n=3) per §6b. Mirrors // Doorway_still_first_frame_diff's own structure (this pose needs // the interior camera cell, unlike the plain outdoor/theory rows). // S3 chunk 1 fix round 1 (G6): kept as its own Fact rather than // folded into Still_fixture_first_frame_reproduces_exactly's Theory // — it and Oh_foundry_deep_... predate that Theory's OH rows and // mirror their own FW0 siblings' structure; either shape works, no // functional reason blocks merging them later. IReadOnlyList frames = WalkOracleTrace.Load( "docs/research/2026-09-01-overhaul/oh-capture", "holtburg-doorway-still.walk"); Assert.NotEmpty(frames); using DatCollection dats = OpenDats(); WalkOracleFrame frame = frames[1]; Assert.NotNull(frame.Pose); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, frame.Pose!.CellId, frame.Pose.Origin); var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells) { Buildings = world.Buildings, }; WalkCell camera = Assert.Contains(frame.Pose.CellId, world.Cells); var walk = new RetailFrameWalk(100f, 0.99f); var recorder = new Recorder(); walk.WalkFrame(frame.Pose.CellId, camera, world.Landscape, ctx, recorder); // S3 chunk 1 fix round 1 (G10): the OH kit pose carries LC/SC/EC/OC // — compare at the full eight-kind level (see Signature8's own doc // comment). string expected = WalkTraceReplayContext.Signature8(frame); string actual = WalkTraceReplayContext.Signature8(recorder.Tokens); Assert.True( expected == actual, $"walk diverged from retail\nEXPECTED: {expected}\nACTUAL: {actual}"); } private const string FwOracleRoot = "docs/research/2026-08-30-fw-walk-oracle"; /// S3 chunk 1 (§11.2 B3): the OH capture directory — its OWN /// pose-stamped kit-pose captures, a DIFFERENT root than the FW0 still /// fixtures above. private const string OhCaptureRoot = "docs/research/2026-09-01-overhaul/oh-capture"; [Theory] [InlineData(FwOracleRoot, "posed/terrace-center")] [InlineData(FwOracleRoot, "posed/terrace-edge")] [InlineData(FwOracleRoot, "posed/cathedral-arrival")] // S3 chunk 1 (§11.2 B3): the OH kit poses, as NEW rows — the OH // cathedral-arrival root is f4180108, NOT FW0's f4180106 (a new pose, // not a replacement of the FW0 row above). [InlineData(OhCaptureRoot, "terrace-edge.walk")] [InlineData(OhCaptureRoot, "cathedral-arrival.walk")] public void Still_fixture_first_frame_reproduces_exactly(string root, string fixture) { IReadOnlyList frames = WalkOracleTrace.Load(root, fixture); Assert.NotEmpty(frames); using DatCollection dats = OpenDats(); WalkOracleFrame frame = frames[1]; Assert.NotNull(frame.Pose); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, frame.Pose!.CellId, frame.Pose.Origin); var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells) { Buildings = world.Buildings, }; WalkCell? camera = (frame.Pose.CellId & 0xFFFFu) >= 0x100 ? Assert.Contains(frame.Pose.CellId, world.Cells) : null; var walk = new RetailFrameWalk(100f, 0.99f); var recorder = new Recorder(); walk.WalkFrame(frame.Pose.CellId, camera, world.Landscape, ctx, recorder); // S3 chunk 1 fix round 1 (G10): the OH kit-pose rows carry // LC/SC/EC/OC — compare THOSE two rows at the full eight-kind level // (Signature8's own doc comment); the FW0 rows have none of those // lines at all (captured before those breakpoints existed), so they // stay on the original four-kind comparison. string expected = root == OhCaptureRoot ? WalkTraceReplayContext.Signature8(frame) : WalkTraceReplayContext.Signature(frame); string actual = root == OhCaptureRoot ? WalkTraceReplayContext.Signature8(recorder.Tokens) : WalkTraceReplayContext.Signature(recorder.Events); Assert.True( expected == actual, $"walk diverged from retail ({fixture})\nEXPECTED: {expected}\nACTUAL: {actual}"); } [Fact] public void Foundry_entry_reproduces_every_frame_before_the_f67_order_segment() { // F67–F79 (the fixture's terminal standing segment) diverge in ONE // aspect: the flood SET through building a9b40036 is exact, but // retail orders its DCs 116,118,11d where the replay orders // 11d,116,118. The microscope isolates the flip to the ROOT plane // of 0036's drawing BSP (N=(0,0,−1) D=2.8): the replay's // building-local eye z is 2.33 (d=+0.47 → NEG-subtree first), while // retail behaves as d<0 (POS-first) — a structural ~0.5 m frame // question (positionPush(2) / part-scale semantics), only // adjudicable by a live cdb dump of FrameCurrent->viewer.viewpoint // during 0036's build_draw_portals_only (script: // tools/walk-oracle/fw1-f67-viewpoint-probe.cdb). Frames 1–66 must // reproduce exactly. MovingFixtureReplay("posed/foundry-entry", stopBeforeFrame: 67); } [Theory] [InlineData("posed/holtburg-walkout")] [InlineData("posed/holtburg-transitions")] [InlineData("posed/holtburg-walkabout")] public void Moving_fixture_reproduces_every_pairable_frame(string fixture) => MovingFixtureReplay(fixture); private void MovingFixtureReplay(string fixture, int stopBeforeFrame = int.MaxValue) { // Marker timing: the pose stamped at frame N+1 is the camera state // frame N drew with (fixture README) — pair events(N) with // pose(N+1). One walk + one landscape carry state across frames, // reproducing retail's cross-frame caches (the stale cell-order // quirk included). IReadOnlyList frames = WalkOracleTrace.Load(fixture); Assert.True(frames.Count >= 3); using DatCollection dats = OpenDats(); WalkOraclePose anchor = frames[1].Pose!; WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build(dats, anchor.CellId, anchor.Origin); var walk = new RetailFrameWalk(100f, 0.99f); for (int n = 1; n < frames.Count - 1; n++) { WalkOracleFrame frame = frames[n]; if (frame.Number >= stopBeforeFrame) break; string expected = WalkTraceReplayContext.Signature(frame); // The marker dumps the PREVIOUS frame's camera, so frame N's // true camera state lies between pose(N) and pose(N+1) — a // capture artifact, not a port ambiguity. A frame passes when // the replay matches under either adjacent pose. string? firstActual = null; bool matched = false; foreach (WalkOraclePose pose in new[] { frames[n + 1].Pose!, frame.Pose! }) { Assert.NotNull(pose); WalkLandscapeDatBuilder.SetViewer(world.Landscape, pose.CellId, pose.Origin); var ctx = new WalkTraceReplayContext(pose, world.Cells) { Buildings = world.Buildings, }; WalkCell? camera = null; if ((pose.CellId & 0xFFFFu) >= 0x100) { Assert.True( world.Cells.TryGetValue(pose.CellId, out camera), $"frame {frame.Number}: interior camera cell {pose.CellId:x8} not loaded"); } var recorder = new Recorder(); walk.WalkFrame(pose.CellId, camera, world.Landscape, ctx, recorder); string actual = WalkTraceReplayContext.Signature(recorder.Events); firstActual ??= actual; if (actual == expected) { matched = true; break; } } Assert.True( matched, $"frame {frame.Number} diverged under both adjacent poses ({fixture})\n" + $"EXPECTED: {expected}\nACTUAL: {firstActual}"); } } [Fact] public void Foundry_deep_reproduces_every_complete_frame_exactly() { IReadOnlyList frames = WalkOracleTrace.Load("posed/foundry-deep"); Assert.NotEmpty(frames); using DatCollection dats = OpenDats(); Dictionary cells = WalkWorldDatAdapter.BuildInteriorCells(dats, 0xA9B40000u); var landscape = new WalkLandscape { MidWidth = 1, Blocks = new WalkLandBlock?[1] }; foreach (WalkOracleFrame frame in frames) { Assert.NotNull(frame.Pose); WalkCell camera = Assert.Contains(frame.Pose!.CellId, cells); var ctx = new WalkTraceReplayContext(frame.Pose, cells); var walk = new RetailFrameWalk(100f, 0.99f); var recorder = new Recorder(); walk.WalkFrame(frame.Pose.CellId, camera, landscape, ctx, recorder); Assert.Equal( WalkTraceReplayContext.Signature(frame), WalkTraceReplayContext.Signature(recorder.Events)); } } [Fact] public void Oh_foundry_deep_reproduces_every_complete_frame_exactly() { // S3 chunk 1 (§11.2 B3): the OH kit pose's own foundry-deep capture // — DI a9b40176, DC(ov=1, n=2), 12 town buildings drawn through the // surviving exit chain (§6b). UNLIKE the FW0 sibling above, this // capture's own retail transcript shows real BLD content at that // depth, so the stub 1x1 landscape (which has no blocks/buildings to // walk at all) undershoots it — first divergence, run without the // fix below: "DI:a9b40176|DC:ov=1:a9b40176,a9b40177|LS" (nothing // after LS) vs retail's "…|LS|BLD:a9b40031|BLD:a9b…" (12 real // buildings). The full landscape/building assembler // (WalkLandscapeDatBuilder.Build — the SAME one the shared theory // and Oh_doorway_still_first_frame_diff use) reproduces them; the // camera is stationary across this still pose, so one build serves // every frame in the loop, matching the FW0 sibling's "build once" // shape. IReadOnlyList frames = WalkOracleTrace.Load( "docs/research/2026-09-01-overhaul/oh-capture", "foundry-deep.walk"); Assert.NotEmpty(frames); using DatCollection dats = OpenDats(); Assert.NotNull(frames[0].Pose); WalkLandscapeDatBuilder.BuiltWorld world = WalkLandscapeDatBuilder.Build( dats, frames[0].Pose!.CellId, frames[0].Pose!.Origin); foreach (WalkOracleFrame frame in frames) { Assert.NotNull(frame.Pose); WalkCell camera = Assert.Contains(frame.Pose!.CellId, world.Cells); var ctx = new WalkTraceReplayContext(frame.Pose, world.Cells) { Buildings = world.Buildings, }; var walk = new RetailFrameWalk(100f, 0.99f); var recorder = new Recorder(); walk.WalkFrame(frame.Pose.CellId, camera, world.Landscape, ctx, recorder); // S3 chunk 1 fix round 1 (G10): full eight-kind comparison — // see Signature8's own doc comment. Assert.Equal( WalkTraceReplayContext.Signature8(frame), WalkTraceReplayContext.Signature8(recorder.Tokens)); } } }