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));
}
}
}