Campaign OVERHAUL S3 chunk 1 (docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md
§11): the transcript-kinds/fixtures/print-only-emitter half of the walk work,
built AFTER chunk 3 landed LC/SC (the per-land-cell interleave).
B1 — the emitter (print-only, never gates admission/depth/order):
- ACDREAM_DUMP_WALK_TRANSCRIPT=1 is read once into RuntimeOptions.DumpWalkTranscript
(rule 4) and handed to RenderingDiagnostics.DumpWalkTranscriptEnabled (rule 5,
a settable static, not a second env read) once at GameWindow construction — the
deep walk call sites have no reachable RuntimeOptions reference.
- WalkTranscriptDump (new) prints the OH line kinds — F/P/LS/LC/SC/BLD/DI/DC/EC/OC —
to Console at the exact points retail's cdb breakpoints sit
(tools/walk-oracle/oh/oh-capture-walk.cdb.template), gated internally so every
method bails out before any string work when the flag is off.
- Every call site lives in WalkFrameDriver.cs, at the point the driver already
processes that turn: Collect (F/P, after BeginFrame), Emit's DI/LS/DC/BLD cases,
OnLandCellTurn/OnLandscapeCellTurn (LC/SC, at LOD resolution via the new
WalkTranscriptDump.LodCellId helper, before the 8x8-bucket expansion), and the
EmitFloodTurns/EmitCellContentsTurn loops (EC/OC — both UNCONDITIONAL per flood
visit, matching the OH captures' always-equal EC/OC counts; retail's own
DrawEnvCell stamp dedupe sits past the breakpoint, inside the function).
- DC's "pv=" field encodes interior(0)/outdoor(1) as an 8-hex-digit 0/1 so it
satisfies the same pv=[0-9a-f]{8} regex real captures use; derived from
_currentDcStage at the DC event (CellStatic = interior pview, else outdoor).
- The frame-root pose (origin, quaternion) is a reasonable orthonormal basis built
from the walk's own CyPlane.Normal forward vector and WalkLandscape's own
ViewerWorldOriginX/Y block origin — self-consistent for the round-trip parser,
not a byte-exact reproduction of retail's Frame (B4's diff never compares P).
B2 — WalkOracleTrace learns EC/OC event kinds (LC/SC already existed from chunk 3).
New WalkOraclePartsTrace.cs holds two small read-only parsers for the parts log
(PD/DM) and the alpha-depth log (AM/FL/PM/PC) — records only, no validator, no
canonical JSONL, no new tool.
B3 — fixtures: the five OH walk captures join WalkOracleTraceTests.AllFixtures
(now (root, name) pairs — FW0's own root plus the OH capture directory) for
parse + complete-frame pins. The four kit poses join WalkTraceConformanceTests'
still-fixture coverage as NEW rows (the OH cathedral-arrival root is f4180108,
not FW0's f4180106): terrace-edge/cathedral-arrival extend the existing theory
(now (root, fixture) parameterized); holtburg-doorway-still and foundry-deep get
dedicated tests mirroring their FW0 siblings' own structure. Finding: the OH
foundry-deep capture's own retail transcript draws 12 real town buildings through
its exit chain (unlike the FW0 capture, which apparently reached none at that
pose) — the FW0 test's stub 1x1 landscape undershoots it (first divergence:
nothing after "LS" vs retail's real BLD content); fixed by building the full
landscape/building world via WalkLandscapeDatBuilder.Build, matching the shared
theory's own approach, not by skipping or weakening the row.
WalkTraceReplayContext.Signature(WalkOracleFrame) now filters to the DI/DC/BLD/LS
kinds (LC/SC/EC/OC never had a WalkEvent analogue in RetailFrameWalk's own
four-kind vocabulary) instead of mapping them to a "?" placeholder, so the still-
fixture comparison stays apples-to-apples on both sides.
B4 — WalkTranscriptSignatureDiff (test-side only, no runner/tool): diffs two
transcripts (raw lines or parsed frames) at the full DI/DC/BLD/LS/LC/SC/EC/OC
level, reporting the first divergent event and position per frame. Proven over a
synthetic self-vs-self-minus-one-event pair (SignatureDiff_ReportsTheExactRemovedEvent).
Tests: T1 (flag off) is split into a unit-level zero-allocation/zero-output check
on WalkTranscriptDump itself (the walk's pre-existing allocation, e.g.
RetailFrameWalk.EmitDrawCells's per-call array, is untouched by this chunk and not
independently zero-alloc) and an integration-level Collect() check; both assert via
WalkOracleTrace.Parse returning zero frames rather than raw string equality, which
is robust to unrelated Console.WriteLine noise from other test classes running in
parallel (a real, observed hazard — WalkFrameDriverTests joins
CameraDiagnosticsCollection for the same reason CornerFloodReplayTests/
Issue181WallPressEquilibriumTests already do, issue #251). T2 proves the
emitter/parser round trip on a synthetic interior frame. T3's InstalledDat rows all
pass. T4: LaunchOptionsDocumentationTests green with the ACDREAM_DUMP_WALK_TRANSCRIPT
row (both directions).
Gates: hermetic lane 6,814/0 (was 6,795 baseline + new tests), three consecutive
clean runs; InstalledDat lane 245/3 known-failures (the two pre-existing #383
layout tests + TowerAscent) unchanged from baseline.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
189 lines
7.2 KiB
C#
189 lines
7.2 KiB
C#
namespace AcDream.App.Tests.Rendering.Walk;
|
|
|
|
/// <summary>
|
|
/// Integrity tests for the FW0 walk-oracle fixtures: every checked-in
|
|
/// trace parses, and the load-bearing shapes recorded in the fixture
|
|
/// README hold. FW1's conformance suite builds on these parsed frames;
|
|
/// if a fixture is edited or recaptured, these goldens catch drift.
|
|
/// </summary>
|
|
public sealed class WalkOracleTraceTests
|
|
{
|
|
private const uint FarBuilding = 0xF518002Eu;
|
|
|
|
private const string FwRoot = "docs/research/2026-08-30-fw-walk-oracle";
|
|
|
|
/// <summary>S3 chunk 1 (§11.2 B3): the OH capture directory. Its walk
|
|
/// logs are named <c><pose>.walk.log</c> — the trailing
|
|
/// <c>.walk</c> below is the fixture-name half of that filename, not a
|
|
/// subdirectory (matching <see cref="WalkLandCellOrderTests"/>'s own
|
|
/// convention).</summary>
|
|
private const string OhRoot = "docs/research/2026-09-01-overhaul/oh-capture";
|
|
|
|
/// <summary>(root, fixture name) pairs. Every FW0 still/posed fixture
|
|
/// keeps its old bare name under <see cref="FwRoot"/>; the five OH
|
|
/// walk captures (§11.2 B3) join under <see cref="OhRoot"/> with the
|
|
/// <c>.walk</c> filename-half suffix.</summary>
|
|
public static readonly TheoryData<string, string> AllFixtures = new()
|
|
{
|
|
{ FwRoot, "terrace-center" },
|
|
{ FwRoot, "terrace-edge" },
|
|
{ FwRoot, "cathedral-arrival" },
|
|
{ FwRoot, "holtburg-doorway-still" },
|
|
{ FwRoot, "holtburg-walkout" },
|
|
{ FwRoot, "holtburg-street-porchcam" },
|
|
{ FwRoot, "holtburg-street-outdoor" },
|
|
{ FwRoot, "holtburg-walkabout" },
|
|
{ FwRoot, "foundry-entry" },
|
|
{ FwRoot, "foundry-deep" },
|
|
{ OhRoot, "holtburg-doorway-still.walk" },
|
|
{ OhRoot, "terrace-edge.walk" },
|
|
{ OhRoot, "cathedral-arrival.walk" },
|
|
{ OhRoot, "foundry-deep.walk" },
|
|
{ OhRoot, "cathedral-leak.walk" },
|
|
};
|
|
|
|
[Theory]
|
|
[MemberData(nameof(AllFixtures))]
|
|
public void Fixture_parses_with_complete_frames(string root, string name)
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load(root, name);
|
|
|
|
Assert.NotEmpty(frames);
|
|
// Frame numbers are contiguous from 1; the truncated final frame is dropped.
|
|
Assert.Equal(1, frames[0].Number);
|
|
Assert.Equal(frames.Count, frames[^1].Number);
|
|
Assert.All(frames, f => Assert.NotEmpty(f.Events));
|
|
}
|
|
|
|
[Fact]
|
|
public void Terrace_edge_draws_the_far_building_every_outdoor_frame()
|
|
{
|
|
// The #456 acceptance oracle: retail HIDES the vista by depth cover,
|
|
// not by omission — 0xF518002E is submitted every single frame.
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("terrace-edge");
|
|
|
|
Assert.All(frames, f =>
|
|
{
|
|
Assert.Null(f.InteriorRootCell);
|
|
Assert.True(f.HasLandscape);
|
|
Assert.Contains(FarBuilding, f.Buildings);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Cathedral_arrival_roots_interior_and_culls_the_far_building()
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("cathedral-arrival");
|
|
|
|
Assert.All(frames, f =>
|
|
{
|
|
Assert.Equal(0xF4180106u, f.InteriorRootCell);
|
|
Assert.True(f.HasLandscape); // drawn THROUGH the exit view
|
|
Assert.DoesNotContain(FarBuilding, f.Buildings);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Doorway_root_is_stable_across_every_frame()
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("holtburg-doorway-still");
|
|
|
|
Assert.All(frames, f => Assert.Equal(0xA9B4013Fu, f.InteriorRootCell));
|
|
}
|
|
|
|
[Fact]
|
|
public void Walkout_hands_over_between_interior_cells_in_one_frame()
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("holtburg-walkout");
|
|
|
|
uint?[] roots = frames.Select(f => f.InteriorRootCell).Distinct().ToArray();
|
|
Assert.Equal(new uint?[] { 0xA9B4013Fu, 0xA9B40150u }, roots);
|
|
// Exactly one handover: the root sequence is two contiguous runs.
|
|
int transitions = frames.Zip(frames.Skip(1))
|
|
.Count(pair => pair.First.InteriorRootCell != pair.Second.InteriorRootCell);
|
|
Assert.Equal(1, transitions);
|
|
}
|
|
|
|
[Fact]
|
|
public void Street_porchcam_roots_at_the_camera_cell_not_the_player()
|
|
{
|
|
// The player stood in the street; the chase camera sat inside the
|
|
// cottage porch — and retail rooted the frame at the CAMERA's cell.
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("holtburg-street-porchcam");
|
|
|
|
Assert.All(frames, f => Assert.Equal(0xA9B40150u, f.InteriorRootCell));
|
|
}
|
|
|
|
[Fact]
|
|
public void Street_outdoor_never_enters_an_interior_root()
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("holtburg-street-outdoor");
|
|
|
|
Assert.All(frames, f =>
|
|
{
|
|
Assert.Null(f.InteriorRootCell);
|
|
Assert.True(f.HasLandscape);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Foundry_entry_flips_outdoor_to_interior_and_drops_the_landscape()
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("foundry-entry");
|
|
|
|
WalkOracleFrame flip = frames.First(f => f.InteriorRootCell is not null);
|
|
Assert.Equal(0xA9B40178u, flip.InteriorRootCell);
|
|
// The frame before the flip is fully outdoor; the flip frame itself
|
|
// draws NO landscape and NO buildings — the pure-interior shape.
|
|
WalkOracleFrame before = frames[flip.Number - 2];
|
|
Assert.Null(before.InteriorRootCell);
|
|
Assert.True(before.HasLandscape);
|
|
Assert.False(flip.HasLandscape);
|
|
Assert.Empty(flip.Buildings);
|
|
}
|
|
|
|
[Fact]
|
|
public void Foundry_deep_draws_the_town_through_the_surviving_chain()
|
|
{
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("foundry-deep");
|
|
|
|
Assert.All(frames, f =>
|
|
{
|
|
Assert.Equal(0xA9B40176u, f.InteriorRootCell);
|
|
Assert.True(f.HasLandscape);
|
|
Assert.NotEmpty(f.Buildings);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Stationary_frames_repeat_their_event_sequence_exactly()
|
|
{
|
|
// README finding 6: while the camera is still, the whole-frame
|
|
// sequence repeats bit-for-bit. Assert it on the terrace fixture.
|
|
IReadOnlyList<WalkOracleFrame> frames = WalkOracleTrace.Load("terrace-center");
|
|
|
|
WalkOracleFrame first = frames[0];
|
|
Assert.All(frames.Skip(1), f =>
|
|
{
|
|
Assert.Equal(first.Events.Count, f.Events.Count);
|
|
for (int i = 0; i < first.Events.Count; i++)
|
|
Assert.Equal(first.Events[i], f.Events[i], WalkOracleEventComparer.Instance);
|
|
});
|
|
}
|
|
|
|
private sealed class WalkOracleEventComparer : IEqualityComparer<WalkOracleEvent>
|
|
{
|
|
public static readonly WalkOracleEventComparer Instance = new();
|
|
|
|
public bool Equals(WalkOracleEvent? x, WalkOracleEvent? y)
|
|
=> x is not null && y is not null
|
|
&& x.Kind == y.Kind
|
|
&& x.CellId == y.CellId
|
|
&& x.OutsideViewCount == y.OutsideViewCount
|
|
&& x.DeclaredCellCount == y.DeclaredCellCount
|
|
&& x.Cells.SequenceEqual(y.Cells);
|
|
|
|
public int GetHashCode(WalkOracleEvent obj)
|
|
=> HashCode.Combine(obj.Kind, obj.CellId, obj.Cells.Count);
|
|
}
|
|
}
|