docs(physics): #347 closed WITHOUT a code change — retail's glide alternates exactly as ours does; AD-70 retired as a wrong inference
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run

The round-2 cdb capture is decisive: during a live retail glide,
edge_slide fired ~1.5 times per find_transitional_position — the
arm/move alternation's exact signature (3 entries on the arming tick,
0 on the moving tick) — with cliff_slide in lockstep, step_down at
2.5x, step_up 0, and every stack sample on our identical call path.
cliff_slide's bytes match our port and ACE's (compare constant at
0x794610 verified 0.0), and the user could not distinguish the two
clients side by side. The "retail redirects within the tick" premise
misread round-1's set_sliding_normal cadence (per-event, not
per-tick, so its 1:1 ratio with edge never discriminated anything).

The alternation-tolerant assertion in Issue345SteepSlopeGlideTests is
therefore the CORRECT retail-shape pin from both sides; its comment
now cites the capture instead of calling the shape a residual. The
#269 note is honest the other way: the hope that a within-tick port
would explain that feel residual is withdrawn with the premise.

The temporary Scratch347 diagnostic is deleted. Capture evidence:
345-glide-stacks.cdb.log (repo root, untracked, cited from the
contract's RESOLUTION section).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-07 14:05:53 +02:00
parent 535f41bbdf
commit fa0c053ebf
5 changed files with 44 additions and 78 deletions

View file

@ -82,9 +82,11 @@ public sealed class Issue345SteepSlopeGlideTests
// 28 of 30 here). The fixed glide alternates: the arming tick
// absorbs the request while edge-slide sets the sliding normal,
// the next tick consumes it and moves (14 of 30 stuck). The
// alternation itself is a KNOWN half-rate residual vs retail's
// within-tick redirect (#347) — this assertion only rejects the
// dead loop. Stuck ticks are counted from positions, not the
// alternation IS retail's own shape — confirmed by the #347
// round-2 cdb capture (345-glide-stacks.cdb.log: ~1.5 edge_slide
// per find_transitional_position during a live glide, the
// alternation's exact signature) — so this range pins it from
// both sides. Stuck ticks are counted from positions, not the
// (temporary) transit-fail probe, so the assertion survives the
// probe family's eventual strip; the lower bound keeps it from
// going vacuous if the fixture stops engaging the face at all.

View file

@ -1,72 +0,0 @@
using System;
using System.IO;
using System.Numerics;
using AcDream.Core.Physics;
using Xunit;
using Xunit.Abstractions;
namespace AcDream.Core.Tests.Physics;
// TEMPORARY #347 diagnostic — deleted before landing.
public sealed class Scratch347DiagTests
{
private readonly ITestOutputHelper _out;
public Scratch347DiagTests(ITestOutputHelper output) => _out = output;
[Fact]
public void DumpFirstArmingTick()
{
var heights = new byte[81];
heights[3 * 9 + 4] = 32;
var heightTable = new float[256];
for (int i = 0; i < 256; i++) heightTable[i] = i;
var engine = new PhysicsEngine();
engine.AddLandblock(0xA9B4FFFFu, new TerrainSurface(heights, heightTable),
Array.Empty<CellSurface>(), Array.Empty<PortalPlane>(), 0f, 0f);
var body = new PhysicsBody
{
State = PhysicsStateFlags.Gravity,
TransientState = TransientStateFlags.Active | TransientStateFlags.Contact | TransientStateFlags.OnWalkable,
};
float dx = 0f, dy = 0.23f;
var position = new Vector3(80.4f, 79.8f, 0f);
uint cell = TerrainSurface.ComputeOutdoorCellId(0xA9B4FFFFu, 80.4f, 79.8f);
PhysicsDiagnostics.DumpTransitFailEnabled = true;
var saved = Console.Out;
var sw = new StringWriter();
Console.SetOut(sw);
try
{
for (int tick = 0; tick < 3; tick++)
{
var result = engine.ResolveWithTransition(
currentPos: position,
targetPos: new Vector3(position.X + dx, position.Y + dy, position.Z),
cellId: cell,
sphereRadius: 0.47f,
sphereHeight: 1.20f,
stepUpHeight: 0.60f,
stepDownHeight: 1.50f,
isOnGround: true,
body: body,
moverFlags: ObjectInfoState.IsPlayer | ObjectInfoState.EdgeSlide,
movingEntityId: 0x5000000Au);
position = result.Position;
cell = result.CellId;
if (tick < 2) sw.GetStringBuilder().Clear(); // keep only the arming tick
}
}
finally
{
Console.SetOut(saved);
PhysicsDiagnostics.DumpTransitFailEnabled = false;
}
foreach (var line in sw.ToString().Split('\n'))
_out.WriteLine(line.TrimEnd());
}
}