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
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:
parent
00c03a33a5
commit
c5443b3df9
5 changed files with 425 additions and 10 deletions
|
|
@ -2170,6 +2170,9 @@ public static class PhysicsDiagnostics
|
|||
// Dump-trigger sets
|
||||
ProbeDumpCellIds = new System.Collections.Generic.HashSet<uint>();
|
||||
ProbeDumpGfxObjIds = new System.Collections.Generic.HashSet<uint>();
|
||||
|
||||
// S6 PerfectClip TOI-tail containment guard (AP-83/AP-91).
|
||||
ResetPerfectClipTailGuardForTest();
|
||||
}
|
||||
|
||||
private static IReadOnlySet<uint> ParseHexIdList(string? raw)
|
||||
|
|
@ -2656,6 +2659,122 @@ public static class PhysicsDiagnostics
|
|||
$"[step-h] site={site} stepUp={stepUp:F3} stepDown={stepDown:F3} {detail}");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// S6 (Campaign S, 2026-08-07) — AP-83/AP-91 PerfectClip TOI-tail
|
||||
// containment guard.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// S6 reachability proof
|
||||
/// (<c>docs/research/2026-08-07-s6-perfectclip-containment-contract.md</c>):
|
||||
/// the ONLY production site that sets
|
||||
/// <see cref="ObjectInfoState.PerfectClip"/> on a mover is
|
||||
/// <c>PhysicsCameraCollisionProbe.SweepEye</c>
|
||||
/// (<c>src/AcDream.App/Rendering/PhysicsCameraCollisionProbe.cs:69</c>),
|
||||
/// which ALSO sets <see cref="ObjectInfoState.IsViewer"/>. The camera's
|
||||
/// resolve DOES reach both the Cyl and Sphere PerfectClip time-of-impact
|
||||
/// tails (<c>TransitionTypes.CylCollideWithPoint</c> / AP-83,
|
||||
/// <c>SphereCollideWithPoint</c> / AP-91) — neither candidate cut from the
|
||||
/// S6 scoping doc holds: <c>CollisionExemption.ShouldSkip</c> only
|
||||
/// exempts a viewer mover against a CREATURE target
|
||||
/// (<c>CollisionExemption.cs:91-94</c>), and
|
||||
/// <c>TransitionTypes.FindObjCollisionsInCell</c> walks every cell's
|
||||
/// shadow list unconditionally, with no viewer/mover-flag gate before the
|
||||
/// per-target loop (called from <c>FindPrimaryCellCollisions</c>,
|
||||
/// <c>TransitionTypes.cs:2477</c>). A non-creature Cyl/Sphere-shaped
|
||||
/// shadow entry is a real production population — static landblock
|
||||
/// scenery registered by <c>LandblockPhysicsPublisher.PublishStaticEntity</c>
|
||||
/// with <c>EntityCollisionFlags.None</c> (tracked live via
|
||||
/// <c>publication.CylinderOwnerCount</c>) — so the camera's foot sphere
|
||||
/// reaches the tail whenever it overlaps one: the camera is always
|
||||
/// PathClipped and never grounded (its resolve passes <c>body: null</c>,
|
||||
/// <c>isOnGround: false</c>), which is exactly Branch 4's PathClipped
|
||||
/// route in both <c>CylinderCollision</c> and <c>SphereCollision</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Call this at the head of the PerfectClip branch inside each TOI tail,
|
||||
/// after confirming <c>ObjectInfo.State</c> carries
|
||||
/// <see cref="ObjectInfoState.PerfectClip"/>. A mover that ALSO carries
|
||||
/// <see cref="ObjectInfoState.IsViewer"/> is the verified-reachable
|
||||
/// population from the proof above — this is expected production
|
||||
/// behavior, not a bug, so it is recorded with a plain counter (never an
|
||||
/// assertion/throw). A mover WITHOUT <c>IsViewer</c> reaching this code
|
||||
/// has no verified reachability chain — the only prior candidate (a
|
||||
/// PathClipped missile) was ported per ACE but never armed PerfectClip in
|
||||
/// M1.5 (<c>PhysicsEngine.cs:1984</c>: "PerfectClip is deliberately not
|
||||
/// inferred"). That population is logged LOUDLY (one-shot per tail) so a
|
||||
/// future flag change cannot silently start executing ACE-derived math
|
||||
/// nobody re-verified.
|
||||
/// </remarks>
|
||||
public static void RecordSpherePerfectClipTailReach(bool moverIsViewer) =>
|
||||
RecordPerfectClipTailReachCore(
|
||||
"Sphere", moverIsViewer,
|
||||
ref _sphereToiCameraLiveCount, ref _sphereToiUnverifiedCount,
|
||||
ref _sphereToiUnverifiedAnnounced);
|
||||
|
||||
/// <inheritdoc cref="RecordSpherePerfectClipTailReach"/>
|
||||
public static void RecordCylPerfectClipTailReach(bool moverIsViewer) =>
|
||||
RecordPerfectClipTailReachCore(
|
||||
"Cyl", moverIsViewer,
|
||||
ref _cylToiCameraLiveCount, ref _cylToiUnverifiedCount,
|
||||
ref _cylToiUnverifiedAnnounced);
|
||||
|
||||
private static void RecordPerfectClipTailReachCore(
|
||||
string tail, bool moverIsViewer,
|
||||
ref int cameraLiveCount, ref int unverifiedCount, ref int unverifiedAnnounced)
|
||||
{
|
||||
if (moverIsViewer)
|
||||
{
|
||||
System.Threading.Interlocked.Increment(ref cameraLiveCount);
|
||||
return;
|
||||
}
|
||||
|
||||
System.Threading.Interlocked.Increment(ref unverifiedCount);
|
||||
if (System.Threading.Interlocked.Exchange(ref unverifiedAnnounced, 1) != 0)
|
||||
return;
|
||||
|
||||
Console.WriteLine(
|
||||
$"[perfectclip-tail] UNVERIFIED mover reached the {tail} PerfectClip "
|
||||
+ "time-of-impact tail (AP-83/AP-91 — ACE-derived math with no retail "
|
||||
+ "decompile; verified-reachable population is the camera / IsViewer "
|
||||
+ "only). A non-viewer mover just executed this path; its reachability "
|
||||
+ "was never re-verified — see "
|
||||
+ "docs/research/2026-08-07-s6-perfectclip-containment-contract.md "
|
||||
+ "before trusting the result.");
|
||||
}
|
||||
|
||||
private static int _sphereToiCameraLiveCount;
|
||||
private static int _sphereToiUnverifiedCount;
|
||||
private static int _sphereToiUnverifiedAnnounced;
|
||||
private static int _cylToiCameraLiveCount;
|
||||
private static int _cylToiUnverifiedCount;
|
||||
private static int _cylToiUnverifiedAnnounced;
|
||||
|
||||
/// <summary>Diagnostic counter — see <see cref="RecordSpherePerfectClipTailReach"/>.</summary>
|
||||
public static int SphereToiCameraLiveCount => _sphereToiCameraLiveCount;
|
||||
/// <summary>Diagnostic counter — see <see cref="RecordSpherePerfectClipTailReach"/>.</summary>
|
||||
public static int SphereToiUnverifiedCount => _sphereToiUnverifiedCount;
|
||||
/// <summary>Diagnostic counter — see <see cref="RecordCylPerfectClipTailReach"/>.</summary>
|
||||
public static int CylToiCameraLiveCount => _cylToiCameraLiveCount;
|
||||
/// <summary>Diagnostic counter — see <see cref="RecordCylPerfectClipTailReach"/>.</summary>
|
||||
public static int CylToiUnverifiedCount => _cylToiUnverifiedCount;
|
||||
|
||||
/// <summary>
|
||||
/// Test-only reset for the S6 PerfectClip-tail guard counters. Does NOT
|
||||
/// reset the one-shot "announced" latches independently of the counts —
|
||||
/// a full reset (counts AND latches) so a sabotage test that intends to
|
||||
/// re-trigger the loud unverified log can observe it fire again.
|
||||
/// </summary>
|
||||
public static void ResetPerfectClipTailGuardForTest()
|
||||
{
|
||||
_sphereToiCameraLiveCount = 0;
|
||||
_sphereToiUnverifiedCount = 0;
|
||||
_sphereToiUnverifiedAnnounced = 0;
|
||||
_cylToiCameraLiveCount = 0;
|
||||
_cylToiUnverifiedCount = 0;
|
||||
_cylToiUnverifiedAnnounced = 0;
|
||||
}
|
||||
|
||||
private static int ParsePositiveInt(string? value) =>
|
||||
int.TryParse(
|
||||
value,
|
||||
|
|
|
|||
|
|
@ -4803,8 +4803,15 @@ public sealed class Transition
|
|||
/// PathClipped movers + airborne head-sphere hits. Non-PerfectClip records the
|
||||
/// center-to-center collision normal and hard-stops (the M1.5 load-bearing
|
||||
/// path — players never set PerfectClip). PerfectClip gets the exact
|
||||
/// time-of-impact reposition (missiles only — AP-91, dead in M1.5, ported per
|
||||
/// ACE Sphere.cs:175-210; re-verify vs Ghidra before missiles ship).
|
||||
/// time-of-impact reposition (ported per ACE Sphere.cs:175-210).
|
||||
///
|
||||
/// <para>
|
||||
/// S6 (AP-91, 2026-08-07): this branch is NOT dead — the camera
|
||||
/// (<c>PhysicsCameraCollisionProbe</c>) sets PerfectClip AND IsViewer on
|
||||
/// every sweep and is not exempted from non-creature Cyl/Sphere shadow
|
||||
/// entries, so it reaches here live in production. See the reachability
|
||||
/// proof on <see cref="PhysicsDiagnostics.RecordSpherePerfectClipTailReach"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private TransitionState SphereCollideWithPoint(ShadowEntry obj, SpherePath sp,
|
||||
Sphere checkSphere, float radsum, int sphereNum)
|
||||
|
|
@ -4819,7 +4826,11 @@ public sealed class Transition
|
|||
return TransitionState.Collided;
|
||||
}
|
||||
|
||||
// PerfectClip exact time-of-impact (AP-91 — dead in M1.5). Block offset = 0.
|
||||
// S6 containment guard (AP-91) — see PhysicsDiagnostics.RecordSpherePerfectClipTailReach.
|
||||
PhysicsDiagnostics.RecordSpherePerfectClipTailReach(
|
||||
(ObjectInfo.State & ObjectInfoState.IsViewer) != 0);
|
||||
|
||||
// PerfectClip exact time-of-impact reposition. Block offset = 0.
|
||||
Vector3 checkOffset = checkSphere.Origin - gCenter;
|
||||
double toi = FindSphereTimeOfCollision(checkOffset, globalOffset, radsum + PhysicsGlobals.EPSILON);
|
||||
if (toi < PhysicsGlobals.EPSILON || toi > 1.0)
|
||||
|
|
@ -5232,10 +5243,17 @@ public sealed class Transition
|
|||
/// PathClipped movers + airborne head-sphere hits. Non-PerfectClip movers
|
||||
/// record the collision normal and hard-stop; PerfectClip movers get the
|
||||
/// exact time-of-impact reposition. TOI sub-branches ported per ACE
|
||||
/// CylSphere.CollideWithPoint (BN mush too heavy in 0x0053adb6+); no
|
||||
/// PerfectClip mover exists in M1.5 (players never set it), so only the
|
||||
/// Collided path is load-bearing today — revisit against Ghidra if
|
||||
/// missiles ever arm PerfectClip (pseudocode doc §7).
|
||||
/// CylSphere.CollideWithPoint (BN mush too heavy in 0x0053adb6+).
|
||||
///
|
||||
/// <para>
|
||||
/// S6 (AP-83, 2026-08-07): this branch is NOT dead — the camera
|
||||
/// (<c>PhysicsCameraCollisionProbe</c>) sets PerfectClip AND IsViewer on
|
||||
/// every sweep and is not exempted from non-creature Cyl-shaped shadow
|
||||
/// entries (e.g. static landblock scenery with a CylSphere and no
|
||||
/// physics BSP), so it reaches here live in production whenever its
|
||||
/// PathClipped foot sphere overlaps one. See the reachability proof on
|
||||
/// <see cref="PhysicsDiagnostics.RecordCylPerfectClipTailReach"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
private TransitionState CylCollideWithPoint(ShadowEntry obj, SpherePath sp,
|
||||
float cylHeight, Sphere checkSphere, Vector3 disp, float radsum, int sphereNum)
|
||||
|
|
@ -5251,6 +5269,10 @@ public sealed class Transition
|
|||
return TransitionState.Collided;
|
||||
}
|
||||
|
||||
// S6 containment guard (AP-83) — see PhysicsDiagnostics.RecordCylPerfectClipTailReach.
|
||||
PhysicsDiagnostics.RecordCylPerfectClipTailReach(
|
||||
(ObjectInfo.State & ObjectInfoState.IsViewer) != 0);
|
||||
|
||||
// Retail reads global_curr_center[0] even for the head hit
|
||||
// (0x0053ad26; ACE agrees) — verbatim.
|
||||
Vector3 globCenter = sp.GlobalCurrCenter[0].Origin;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue