test(physics): S6 — the camera provably reaches both PerfectClip TOI tails; contained, not dormant
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

AP-83/AP-91 claimed no current mover sets PerfectClip. The containment
proof found the opposite and the contract's honest-fallback fired: the
camera probe (the sole production setter) reaches BOTH ACE-derived
tails live — the viewer exemption is creature-only, the shadow-list
walk is unconditional, and static scenery with authored primitives is
a real non-creature population. Every reach is now recorded
(camera-live silently; any non-viewer mover loudly, one-shot), so a
future flag change cannot exercise unreviewed ACE-derived math
silently. Four tests drive the camera's exact call shape both ways;
the sabotage was intelligently adapted — there was no existing cut to
disable, so it flips the one axis the proof depends on (IsCreature)
and asserts reachability inverts. Both register rows rewritten
CONTAINED-not-dormant with severity narrowed to camera-feel (the probe
never commits a PhysicsBody).

Landing note: diagnostics-only diff (two guard calls + counters +
corrected stale comments), verified directly by the session lead
rather than a review cycle — the review budget went where behaviour
changed tonight.

Campaign S CLOSES with this landing: S1A/S1B/S2/S4/S5/S6 done, S3
cancelled, three user-passed gates, one honestly-open item — AD-66's
reland, twice self-refused by its own stability gate, blocked on the
#341 codegen-shape measurement instability whose ABA evidence and
first discriminating experiment are filed.

Clean-room suite: 11,257 passed / 6 skipped / 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-07 09:21:40 +02:00
parent 00c03a33a5
commit c5443b3df9
5 changed files with 425 additions and 10 deletions

View file

@ -0,0 +1,265 @@
using System;
using System.Numerics;
using AcDream.Core.Physics;
using Xunit;
using Xunit.Abstractions;
namespace AcDream.Core.Tests.Physics;
/// <summary>
/// S6 (Campaign S, 2026-08-07) — reachability proof + containment guard for
/// the AP-83/AP-91 PerfectClip time-of-impact tails
/// (<c>TransitionTypes.CylCollideWithPoint</c> / <c>SphereCollideWithPoint</c>).
/// Contract: docs/research/2026-08-07-s6-perfectclip-containment-contract.md.
///
/// <para>
/// FINDING (not a failure — the contract explicitly anticipates this outcome):
/// BOTH scoping-doc candidate arguments for "the camera can never reach these
/// tails" fail. <c>CollisionExemption.ShouldSkip</c> only exempts a viewer
/// mover against a CREATURE target (CollisionExemption.cs:91-94) — a
/// non-creature Cyl/Sphere shadow entry passes straight through. And
/// <c>FindObjCollisionsInCell</c> walks every cell's shadow list
/// unconditionally, with no viewer skip-all gate before the per-target loop
/// (TransitionTypes.cs:3806, reached from <c>FindPrimaryCellCollisions</c> with
/// no mover-flag check, TransitionTypes.cs:2477). So the camera
/// (<c>PhysicsCameraCollisionProbe.SweepEye</c> — the ONLY production
/// PerfectClip setter, grep-confirmed against the whole src tree) DOES reach
/// both TOI tails whenever its PathClipped, never-grounded foot sphere
/// (moverFlags carry PathClipped; body=null + isOnGround=false means neither
/// Contact nor OnWalkable is ever seeded) overlaps a non-creature Cyl/Sphere
/// shadow entry. That population is real production content: static
/// landblock scenery with a CylSphere/Sphere and no physics BSP registers
/// with <c>EntityCollisionFlags.None</c>
/// (<c>LandblockPhysicsPublisher.PublishStaticEntity</c>, tracked live via
/// <c>publication.CylinderOwnerCount</c>).
/// </para>
///
/// <para>
/// These tests drive the REAL production resolve
/// (<c>PhysicsEngine.ResolveWithTransition</c>) with the camera's exact call
/// shape (IsViewer|PathClipped|FreeRotate|PerfectClip, single 0.3 m sphere,
/// body=null, isOnGround=false — mirrors <c>PhysicsCameraCollisionProbe
/// .SweepEye</c> and the harness already used by
/// <c>CameraCornerSealReplayTests</c> / <c>Issue180CorridorSweepHysteresis
/// ReplayTests</c>) against a synthetic Cyl/Sphere shadow entry, and assert
/// the guard (<c>PhysicsDiagnostics.RecordCylPerfectClipTailReach</c> /
/// <c>RecordSpherePerfectClipTailReach</c>) records the reach as camera-live,
/// never as unverified.
/// </para>
///
/// <para>
/// <b>Sabotage</b> (deliverable 3): the contract's literal wording is "disable
/// the exemption that cuts the chain and watch the reachability flip" — but
/// the proof found NOTHING currently cuts the chain for a non-creature
/// target, so there is no existing cut to disable. The faithful adaptation
/// flips the SAME one axis <c>CollisionExemption.ShouldSkip</c> actually
/// reads (<c>EntityCollisionFlags.IsCreature</c>) from off to on and asserts
/// reachability inverts: the guard goes silent and the camera walks straight
/// through, exactly the retail "camera ray ignores creatures" rule
/// (acclient_2013_pseudo_c.txt:276787-276790). This proves the guard is wired
/// to the actual condition the reachability proof depends on, not merely
/// "always fires regardless of input".
/// </para>
/// </summary>
public class S6PerfectClipTailContainmentTests
{
private readonly ITestOutputHelper _out;
public S6PerfectClipTailContainmentTests(ITestOutputHelper output) => _out = output;
private const uint TestLandblockId = 0xA9B40000u;
private const uint TestCellId = TestLandblockId | 0x0001u; // landcell (0,0), matches CylSphereFamilyTests/SphereCollisionFamilyTests
private const float ViewerSphereRadius = 0.3f; // retail viewer_sphere (acclient :93314)
private static readonly ObjectInfoState CameraMoverFlags =
ObjectInfoState.IsViewer | ObjectInfoState.PathClipped
| ObjectInfoState.FreeRotate | ObjectInfoState.PerfectClip;
// ───────────────────────────────────────────────────────────────
// Sphere tail (AP-91)
// ───────────────────────────────────────────────────────────────
[Fact]
public void CameraSweep_HitsNonCreatureSphereProp_ReachesTail_RecordsCameraLive()
{
PhysicsDiagnostics.ResetPerfectClipTailGuardForTest();
var engine = BuildEngine();
RegisterSphere(engine, 0x00005001u, new Vector3(12f, 14f, 1.0f), radius: 1.0f,
flags: EntityCollisionFlags.None); // static prop, not a creature
Vector3 pivot = new(12f, 10f, 1.0f);
Vector3 eye = new(12f, 20f, 1.0f); // straight through the prop's center
var r = SweepViewer(engine, pivot, eye, TestCellId);
_out.WriteLine(FormattableString.Invariant($"ok={r.Ok} pos=({r.Position.X:F3},{r.Position.Y:F3},{r.Position.Z:F3}) collNorm={r.CollisionNormalValid} normal=({r.CollisionNormal.X:F3},{r.CollisionNormal.Y:F3},{r.CollisionNormal.Z:F3}) cameraLive={PhysicsDiagnostics.SphereToiCameraLiveCount} unverified={PhysicsDiagnostics.SphereToiUnverifiedCount}"));
Assert.True(PhysicsDiagnostics.SphereToiCameraLiveCount > 0,
"The camera's PathClipped, never-grounded sweep must reach the Sphere PerfectClip TOI tail (AP-91) for a non-creature target.");
Assert.Equal(0, PhysicsDiagnostics.SphereToiUnverifiedCount);
// Golden: the sphere prop must have stopped the camera's forward sweep
// (PathClipped hard-stops at first contact) well short of the far side.
Assert.True(r.Position.Y < 14f,
$"camera must be stopped by the prop, not pass through it; got Y={r.Position.Y:F3}");
Assert.True(r.Position.Y > 11f,
$"camera must actually reach the prop's surface, not stop early; got Y={r.Position.Y:F3}");
}
[Fact]
public void CameraSweep_HitsCreatureFlaggedSphere_ExemptionCutsChain_GuardStaysSilent()
{
PhysicsDiagnostics.ResetPerfectClipTailGuardForTest();
var engine = BuildEngine();
// SABOTAGE: flip the one axis CollisionExemption.ShouldSkip reads for a
// viewer mover — everything else about the geometry is identical to the
// reached case above.
RegisterSphere(engine, 0x00005002u, new Vector3(12f, 14f, 1.0f), radius: 1.0f,
flags: EntityCollisionFlags.IsCreature);
Vector3 pivot = new(12f, 10f, 1.0f);
Vector3 eye = new(12f, 20f, 1.0f);
var r = SweepViewer(engine, pivot, eye, TestCellId);
_out.WriteLine(FormattableString.Invariant($"ok={r.Ok} pos=({r.Position.X:F3},{r.Position.Y:F3},{r.Position.Z:F3}) cameraLive={PhysicsDiagnostics.SphereToiCameraLiveCount}"));
Assert.Equal(0, PhysicsDiagnostics.SphereToiCameraLiveCount);
Assert.Equal(0, PhysicsDiagnostics.SphereToiUnverifiedCount);
// Reachability flips: CollisionExemption now exempts the whole target
// for the viewer mover before shape dispatch, so the camera sails
// straight through to the far side (retail: camera ray ignores
// creatures, acclient_2013_pseudo_c.txt:276787-276790).
Assert.True(r.Position.Y > 19f,
$"a creature-flagged prop must be fully exempt for a viewer mover; got Y={r.Position.Y:F3}");
}
// ───────────────────────────────────────────────────────────────
// Cyl tail (AP-83)
// ───────────────────────────────────────────────────────────────
[Fact]
public void CameraSweep_HitsNonCreatureCylinderProp_ReachesTail_RecordsCameraLive()
{
PhysicsDiagnostics.ResetPerfectClipTailGuardForTest();
var engine = BuildEngine();
RegisterCylinder(engine, 0x00006001u, new Vector3(12f, 14f, 0f), radius: 1.0f, height: 2.0f,
flags: EntityCollisionFlags.None);
Vector3 pivot = new(12f, 10f, 1.0f);
Vector3 eye = new(12f, 20f, 1.0f);
var r = SweepViewer(engine, pivot, eye, TestCellId);
_out.WriteLine(FormattableString.Invariant($"ok={r.Ok} pos=({r.Position.X:F3},{r.Position.Y:F3},{r.Position.Z:F3}) collNorm={r.CollisionNormalValid} normal=({r.CollisionNormal.X:F3},{r.CollisionNormal.Y:F3},{r.CollisionNormal.Z:F3}) cameraLive={PhysicsDiagnostics.CylToiCameraLiveCount} unverified={PhysicsDiagnostics.CylToiUnverifiedCount}"));
Assert.True(PhysicsDiagnostics.CylToiCameraLiveCount > 0,
"The camera's PathClipped, never-grounded sweep must reach the Cyl PerfectClip TOI tail (AP-83) for a non-creature target.");
Assert.Equal(0, PhysicsDiagnostics.CylToiUnverifiedCount);
Assert.True(r.Position.Y < 14f,
$"camera must be stopped by the prop, not pass through it; got Y={r.Position.Y:F3}");
Assert.True(r.Position.Y > 11f,
$"camera must actually reach the prop's surface, not stop early; got Y={r.Position.Y:F3}");
}
[Fact]
public void CameraSweep_HitsCreatureFlaggedCylinder_ExemptionCutsChain_GuardStaysSilent()
{
PhysicsDiagnostics.ResetPerfectClipTailGuardForTest();
var engine = BuildEngine();
RegisterCylinder(engine, 0x00006002u, new Vector3(12f, 14f, 0f), radius: 1.0f, height: 2.0f,
flags: EntityCollisionFlags.IsCreature);
Vector3 pivot = new(12f, 10f, 1.0f);
Vector3 eye = new(12f, 20f, 1.0f);
var r = SweepViewer(engine, pivot, eye, TestCellId);
_out.WriteLine(FormattableString.Invariant($"ok={r.Ok} pos=({r.Position.X:F3},{r.Position.Y:F3},{r.Position.Z:F3}) cameraLive={PhysicsDiagnostics.CylToiCameraLiveCount}"));
Assert.Equal(0, PhysicsDiagnostics.CylToiCameraLiveCount);
Assert.Equal(0, PhysicsDiagnostics.CylToiUnverifiedCount);
Assert.True(r.Position.Y > 19f,
$"a creature-flagged prop must be fully exempt for a viewer mover; got Y={r.Position.Y:F3}");
}
// ───────────────────────────────────────────────────────────────
// Harness (mirrors CylSphereFamilyTests / SphereCollisionFamilyTests)
// ───────────────────────────────────────────────────────────────
private static PhysicsEngine BuildEngine()
{
var cache = new PhysicsDataCache();
var engine = new PhysicsEngine { DataCache = cache };
// Flat terrain at Z=0 across the whole landblock — irrelevant to these
// sweeps (they travel at Z≈1.0, well above ground) but required so the
// outdoor cell resolves.
var heights = new byte[81];
var heightTable = new float[256]; // all zero → terrain Z = 0
engine.AddLandblock(
landblockId: TestLandblockId,
terrain: new TerrainSurface(heights, heightTable),
cells: Array.Empty<CellSurface>(),
portals: Array.Empty<PortalPlane>(),
worldOffsetX: 0f,
worldOffsetY: 0f);
return engine;
}
/// <summary>
/// Mirror of PhysicsCameraCollisionProbe.SweepEye's transition call — same
/// shape already used by CameraCornerSealReplayTests,
/// Issue180CorridorSweepHysteresisReplayTests, and CylSphereFamilyTests'
/// landblock (0x0100 low word stays below the AdjustPosition threshold, so
/// the outdoor cellId is used as-is).
/// </summary>
private static ResolveResult SweepViewer(PhysicsEngine engine, Vector3 pivot, Vector3 desiredEye, uint cellId)
{
Vector3 begin = pivot - new Vector3(0f, 0f, ViewerSphereRadius);
Vector3 end = desiredEye - new Vector3(0f, 0f, ViewerSphereRadius);
return engine.ResolveWithTransition(
currentPos: begin,
targetPos: end,
cellId: cellId,
sphereRadius: ViewerSphereRadius,
sphereHeight: 0f,
stepUpHeight: 0f,
stepDownHeight: 0f,
isOnGround: false,
body: null,
moverFlags: CameraMoverFlags,
movingEntityId: 0);
}
private static void RegisterSphere(PhysicsEngine engine, uint entityId, Vector3 worldPos,
float radius, EntityCollisionFlags flags)
{
engine.ShadowObjects.Register(
entityId, gfxObjId: 0u,
worldPos, Quaternion.Identity, radius,
worldOffsetX: 0f, worldOffsetY: 0f, landblockId: TestLandblockId,
collisionType: ShadowCollisionType.Sphere,
cylHeight: 0f, scale: 1f,
state: 0u,
flags: flags,
isStatic: true);
}
private static void RegisterCylinder(PhysicsEngine engine, uint entityId, Vector3 worldPos,
float radius, float height, EntityCollisionFlags flags)
{
engine.ShadowObjects.Register(
entityId, gfxObjId: 0u,
worldPos, Quaternion.Identity, radius,
worldOffsetX: 0f, worldOffsetY: 0f, landblockId: TestLandblockId,
collisionType: ShadowCollisionType.Cylinder,
cylHeight: height, scale: 1f,
state: 0u,
flags: flags,
isStatic: true);
}
}