fix(physics): P5 commit 3 - retire TS-35, close #167 (ConstraintManager leash)

PhysicsBody.IsFullyConstrained now reflects real ConstraintManager state
(pushed every tick by the same per-tick pumps commit 2 wired), so
jump_is_allowed's already-ported gate (WeenieError 0x47) actually fires
while an object is rubber-banding hard against a server position
correction, closing the last piece of #167.

Housekeeping:
- Delete register row TS-35 (retired: the write side is no longer stubbed).
- Rewrite the stale doc comments on PhysicsBody.IsFullyConstrained,
  ConstraintManager (class + IsFullyConstrained), PositionManager.ConstrainTo,
  EntityPhysicsHost.PositionManager, and PlayerMovementController.PositionManager
  that described the leash as permanently unarmed/stubbed.
- Close #167 in ISSUES.md citing the research doc and commits e0629145 /
  7719d25b.
- Add an "as-ported" addendum to
  docs/research/2026-07-30-constraint-leash-constants.md naming the actual
  current seam owners (the doc's own open question flagged this as
  implementer-verify-required post-J-slices).
- Update docs/plans/2026-07-29-physics-parity-campaign.md's P5 status and
  CLAUDE.md's Campaign P summary to reflect #167's closure (items #153/#72
  remain open in P5).

Verification: complete solution suite green - 9,978 tests, 5 skips, 0
failures across all 9 test projects (Core.Tests, Runtime.Tests, App.Tests,
Headless.Tests, Core.Net.Tests, Content.Tests, UI.Abstractions.Tests,
Bake.Tests, Cli.Tests).
This commit is contained in:
Erik 2026-07-30 12:12:29 +02:00
parent 7719d25bc5
commit 9e17554ed4
10 changed files with 159 additions and 48 deletions

View file

@ -408,16 +408,33 @@ public sealed class PhysicsBody
public double LastUpdateTime { get; set; }
/// <summary>
/// R3-W3 stub for retail <c>CPhysicsObj::IsFullyConstrained</c>
/// (0x0050f730), read by <c>CMotionInterp::jump_is_allowed</c> (raw
/// 305524-305525: <c>if (IsFullyConstrained(physics_obj) != 0) return
/// 0x47;</c>). Retail's body walks per-cell contact-plane constraints
/// (a mover pinned between opposing walkable surfaces / doorway
/// jamming); acdream has no equivalent constraint-tracking yet.
/// Register row: stubbed false (never fires) — a real port needs the
/// per-cell shadow-list contact accounting the physics digest tracks.
/// See docs/architecture/retail-divergence-register.md (added same
/// commit as this field).
/// Retail <c>CPhysicsObj::IsFullyConstrained</c> (0x0050f730), read by
/// <c>CMotionInterp::jump_is_allowed</c> (raw 305524-305525:
/// <c>if (IsFullyConstrained(physics_obj) != 0) return 0x47;</c>) to block
/// a jump while the object is rubber-banding hard against a server
/// position correction.
///
/// <para>R3-W3 originally stubbed this as an always-false property under
/// a WRONG mechanism guess (per-cell contact-plane / doorway-jamming).
/// R5-V1 corrected the mechanism: the real retail source is
/// <c>ConstraintManager::IsFullyConstrained</c> (0x005560d0,
/// <c>constraint_distance_max * 0.9 &lt; constraint_pos_offset</c>) —
/// <see cref="Motion.PositionManager"/>'s constraint sub-manager. R5-V1
/// ported <see cref="Motion.ConstraintManager"/> but did not arm it (#167,
/// former register row TS-35).</para>
///
/// <para>Campaign P P5 (2026-07-30) armed the leash at every current
/// inbound-position acceptance seam
/// (<c>LiveEntityNetworkUpdateController</c> for remotes,
/// <c>PlayerMovementController.SetPosition</c>/<c>BlipPosition</c> for the
/// local player — see <c>docs/research/2026-07-30-constraint-leash-constants.md</c>
/// §2/§3). <see cref="MotionInterpreter"/> only holds a
/// <see cref="PhysicsBody"/> reference (no host), so this property stays a
/// plain settable bool; the per-tick pump that already runs
/// <c>PositionManager.AdjustOffset</c> (<c>PlayerMovementController.Update</c>,
/// <c>RuntimeRemotePhysicsUpdater.Tick</c>/<c>TickHidden</c>) is the single
/// owner that pushes <c>PositionManager.IsFullyConstrained()</c> here every
/// tick, so this read is now live, not stubbed.</para>
/// </summary>
public bool IsFullyConstrained { get; set; }