acdream/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceConformanceTests.cs
Erik 88c70072e0 fix(render): S3 chunk 1 round 2 — one weather OC per frame (pinned), literal EC/OC comparison, comment/cost/wording items
Campaign OVERHAUL S3 chunk 1 fix round 2 (docs/research/2026-09-01-overhaul/
s3-walk-ownership-map.md §11.6), applied on top of 36be6b598 after the
three-lens re-review. H1-H6, the last round the plan allows.

H1 — the weather OC printed 2-4 times per interior-rooted frame instead of
once: the print (and the `_sky.RenderWeather` mesh draw it sits beside) lived
inside `DrawLandscapeSliceLate`, which `RetailPViewRenderer` calls once per
active `OutsideViewSlices` entry. Moved both into a new
`RetailPViewPassExecutor.DrawWeatherOnce`, called ONCE, unclipped/no-scissor,
after the slice loop in `DrawLandscapeDynamicsPhase` — retail's own
`GameSky::Draw(1)` runs once, after `LScape::draw`'s whole landblock loop.
The gate is extracted as a pure `ShouldDrawWeatherOnce(bool,bool,uint)`
predicate (retail's `SmartBox::is_player_outside` ANDed with the two render
toggles) so `RetailPViewPassExecutorTests` can pin "no OC while the player
stands indoors" without a live GL/DAT `SkyRenderer`; two structural
(CompiledCallGraph) tests prove the call moved out of the per-slice loop and
that the mesh draw + print each fire exactly once per invocation — this
codebase has no existing runtime-construction fixture for
`RetailPViewPassExecutor`, so the pin is structural + a testable pure gate
rather than an end-to-end GL drive. One deliberate deviation from the literal
"gated exactly as today": the print now runs through `_sky?.RenderWeather(...)`
(null-conditional, matching every other `_sky?.RenderSky(...)` call site in
this codebase) instead of an explicit `if (_sky is not null)` wrapper — a
missing sky asset no longer also suppresses the transcript print, since the
print's only job is trace fidelity and retail's own `GameSky` is never null.

H2 — WalkFrameDriver's EC-print comment still claimed "EC and OC counts are
always exactly equal"; replaced with the real citation
(holtburg-doorway-still.walk.log:1126,1131,1134,1137 — four EC prints for one
cell across four look-in DC turns), matching WalkTranscriptDump.
PrintEnvCellShell's own comment (already corrected in round 1).

H3 — the eight-kind signature's ORACLE side
(WalkTraceReplayContext.Signature8(WalkOracleFrame)) derived EC/OC from each
DC's cell list — the SAME derivation the REPLAY side's Recorder already used,
so the comparison could never disagree with itself on EC/OC placement or
content (how G7's SC-ordering regression shipped green with LC/SC). Now reads
its own literally captured EC/OC events, excluding only the trailing
per-frame weather OC — refined beyond the spec's literal "last event + P-cell
id" rule with an additional "P cell itself looks outdoor" check, after
cathedral-arrival and foundry-deep both proved the naive rule also strips an
interior root's OWN real trailing object-list turn when its nearest cell (the
reversed flood loop's last draw) happens to be the camera's own root cell.
All four kit-pose rows still reproduce: three exactly; #458 (this round's new
issue, formerly an inline-only note) re-verified at the SAME token index 165
under the new literal comparison.

H4 — OnSortCellTurn ran RequireOpenFrame + two range validations before
testing the flag. Since the hook is print-only (no stream side effect, unlike
OnLandCellTurn's unconditional WalkFrameEvent record), the flag check now
runs FIRST and returns immediately when off — flag-off cost drops to one
interface dispatch per visited land cell.

H5 — launch-options.md's ACDREAM_DUMP_WALK_TRANSCRIPT row: measured
≈1,200-1,400 lines per outdoor frame (terrace-edge 1,384; cathedral-arrival
1,269; doorway 1,187), replacing the earlier "600-800" estimate; documents
H4's residual flag-off interface-dispatch cost.

H6 — filed docs/ISSUES.md #458 for round 1's LOD-boundary land-cell
divergence (previously only an inline test comment); the InstalledDat lane's
known-failure set is now four (two #383 layout tests, TowerAscent, #458) —
confirmed by a clean run.

MUTATION CHECKS (both restored after confirming failure):
- H1: deleting the OC print inside DrawWeatherOnce made
  DrawWeatherOnce_DrawsTheWeatherMeshAndPrintsExactlyOnce fail with
  "Assert.Single() Failure: The collection did not contain any matching
  items".
- H3: reversing AppendFloodTurns (OC before EC) made
  Still_fixture_first_frame_reproduces_exactly(cathedral-arrival.walk) fail
  ("walk diverged from retail (cathedral-arrival.walk)"), diverging at token
  index 1241: expected "EC:f4180112" vs actual "OC:f4180112".

Gates: hermetic App suite 6823/6823 passed; InstalledDat lane 244/249 passed
with exactly the four known failures (two #383 layout tests, TowerAscent,

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 12:30:30 +02:00

440 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AcDream.App.Tests.Rendering;
using AcDream.App.Rendering.Walk;
using DatReaderWriter;
using DatReaderWriter.Options;
namespace AcDream.App.Tests.Rendering.Walk;
/// <summary>
/// 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.
/// </summary>
[Trait("Lane", "InstalledDat")]
public sealed class WalkTraceConformanceTests
{
/// <summary>S3 chunk 1 fix round 1 (G10): besides the plain
/// <see cref="WalkEvent"/> list the four-kind
/// <see cref="WalkTraceReplayContext.Signature(IEnumerable{WalkEvent})"/>
/// still uses, also builds the full eight-kind token stream — LS/BLD/
/// DI/DC/LC/SC/EC/OC — AS each hook fires, for
/// <see cref="WalkTraceReplayContext.Signature8(IReadOnlyList{string})"/>.
/// <see cref="_lookIn"/> mirrors <c>WalkFrameDriver</c>'s own private
/// <c>_currentDcStage</c>: null until the frame's first
/// <see cref="WalkEventKind.DrawInside"/> (the interior root's own
/// flood defers its EC/OC to <see cref="OnInteriorFloodDrawTurn"/>),
/// flips true forever once a building's portal pass begins
/// (<see cref="OnBuildingTurn"/>) — see
/// <see cref="WalkTraceReplayContext.AppendFloodTurns"/>'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 (<see cref="WalkTraceReplayContext.Signature8(WalkOracleFrame)"/>)
/// moved off derivation onto its own literal captured EC/OC lines.</summary>
private sealed class Recorder : IWalkEventSink
{
public readonly List<WalkEvent> Events = new();
public readonly List<string> 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<uint> cells, int outsideViewCount)
=> WalkTraceReplayContext.AppendFloodTurns(Tokens, cells);
}
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<WalkOracleFrame> 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();
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<WalkOracleFrame> 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 { DegradeMultiplier = 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}");
}
/// <summary>
/// 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 —
/// <c>…SC:a8c90001|LC:a8c90001|SC:a8c90001|</c> retail jumps straight to
/// <c>LC:95c60001</c>; the replay inserts <c>LC:a9c90001|SC:a9c90001</c>
/// first. A single spurious block admission at a ring-2/ring-3 LOD
/// boundary near this pose — a real <c>WalkLandscape.CheckBlocks</c>
/// 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.
/// </summary>
[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<WalkOracleFrame> 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();
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";
/// <summary>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.</summary>
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<WalkOracleFrame> 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();
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()
{
// F67F79 (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 166 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<WalkOracleFrame> 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();
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<WalkOracleFrame> frames = WalkOracleTrace.Load("posed/foundry-deep");
Assert.NotEmpty(frames);
using DatCollection dats = OpenDats();
Dictionary<uint, WalkCell> 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();
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<WalkOracleFrame> 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();
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));
}
}
}