acdream/docs/research/2026-08-06-ad10-review-retail.md
Erik 7b3e2895cd docs: close the AD-10 review findings — AD-65's magnitude was half the truth
Both AD-10 review lenses PASS; the deletion stands. These are the findings
they raised. One production file touched, comment-only.

AD-65 WAS UNDERSTATED BY HALF, and it is the finding that matters. The row
states the factor as cos^2(theta) and then quantified 1-cos(theta): "13% at
30 degrees, 29% at 45". The correct figures are 25% and 50%. This is not
algebra alone — #331's probe in the same push measures 0.0735 m travelled for
a 0.1 m request at 30.96 degrees, i.e. 26.5% short, which is exactly
cos^2(30.96). AD-65 is a LEAD for #269's slope-slide residual; at the
understated magnitude it reads as marginal and could have been dismissed. At
50% short at 45 degrees it is a serious candidate. I repeated the wrong figure
in conversation before the review caught it.

"VERBATIM/FAITHFUL PORT" of Transition.AdjustOffset was asserted in five
places and was false as of the very next commit, which filed AD-65 and AD-66
against that same function. Corrected to "structurally exact, with exactly two
filed divergences" in the register row and the production doc comment.

RECORDED, and it favours the change: the redundancy measurement is CONTINGENT
on AD-65 — the two mechanisms agree today partly because both under-travel
downhill. That makes this deletion a PREREQUISITE for fixing AD-65 rather than
merely compatible with it; had the projection survived, correcting
AdjustOffset would have re-introduced a disagreement between two live
projections. The record claimed no such thing and should have.

UNTESTED AXIS recorded: the contract's T2 — its mandatory wrong-plane-versus-
right-plane discriminator — was dropped without record, breaching the
contract's own clause requiring exactly that to be written down. The
consequence is precise: the deletion is measured, but the change's only
claimed BENEFIT (a walkable non-terrain surface now gets the committed contact
plane instead of terrain far below) has zero automated coverage and rests on
source reasoning. Stated in the row rather than left implied.

#331 SEVERITY RAISED from UNKNOWN — the discriminator is known and it is not
the fixture. With `body: null` the same uphill sweep climbs (ok=True, moved
(0, -0.0999, +0.060)); with a body supplied it returns ok=False and zero
movement, under a call profile identical to the local player's
(IsPlayer|EdgeSlide + the human two-sphere Setup). A diagonal request keeps
cross-slope X and zeroes only up-slope Y, and it fires on a 1.1 degree ramp.
So "confined to the synthetic fixture" is no longer the comfortable default:
the failing call shape is the shape production uses. Nothing in the suite
asserts uphill progress on a walkable slope, which is why it was invisible —
the test that found it passed vacuously, because the body never moved.

Also: malformed XML doc on ComposeOffset (duplicate </summary> swallowed the
retirement note from tooling) fixed; the placement-cutover plan's item 5 and
its stale "After C5" line now record AP-22 and AD-10 as retired.

Core builds clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 10:08:53 +02:00

26 KiB
Raw Permalink Blame History

AD-10 retirement — retail-conformance review

Verdict: PASS, with one MEDIUM documentation defect that must be corrected before the register row is trusted (AD-65's quantification), and three LOW items.

  • Reviewed: ef976c6d..2223ed17 on claude/acdream-physics-divergence-5aa784 in worktree .claude/worktrees/peaceful-visvesvaraya-e0a196 (fe6ee877, 886333a2, fb454b74, 2223ed17).
  • Lens: retail conformance. Every retail claim below was re-derived from the PDB-paired binary, not from the contract, the commit messages, or the Binary Ninja pseudo-C.
  • Binary: C:\Users\erikn\Downloads\acclient.exe, check_exe_pdb.py=== MATCH ===, linker UTC 2013-09-06T00:17:56, CodeView GUID 9e847e2f-777c-4bd9-886c-22256bb87f32. Image base 0x00400000. Disassembled with capstone x86-32 straight off the file, VA→file-offset through the section table; floats read from .rdata as raw bytes.
  • Build/test: all 44 bin/obj directories deleted, full dotnet build AcDream.slnx -c Release0 errors; full dotnet test --no-build0 failed. Staleness disproved positively: SampleTerrainNormal is absent from the freshly built AcDream.Core.dll byte image (and RuntimeRemoteSlopeProjectionTests is present in the test image), so the runner is genuinely serving the deleted code.

1. Independent verification of the retail claims

1.1 Is Transition.AdjustOffset a faithful port of CTransition::adjust_offset @0x0050a370?

Yes — structurally exact, with exactly the two exceptions the change itself filed as AD-65 and AD-66. No third divergence found.

Function extent from the binary: 0x0050a370 (sub esp,0x24) to 0x0050a6c7 (ret 8), nops to 0x0050a6d0 where CTransition::cliff_slide begins. Symbol confirmed from symbols.json: 0x0050A370 CTransition::adjust_offset, mangled ?adjust_offset@CTransition@@IAE?AVVector3@AC1Legacy@@ABV23@@Z (returns Vector3, takes const Vector3&).

Field map recovered from the code: this+0x2a8 = sliding_normal_valid, this+0x2ac/0x2b0/0x2b4 = sliding_normal.xyz, this+0x288 = contact_plane_valid, esi = this+0x28c = contact_plane (N.x/N.y/N.z at +0/+4/+8, D at +0xc), this+0x2a4 = contact_plane_is_water, this+0x29c = contact_plane_cell_id, this+0x34 → global sphere (origin +0/+4/+8, radius +0xc), this+0x20 = sphere path.

All four x87 flag tests decoded (the contract's count is right; here is each one, with the FPU condition-code reasoning — fcom* sets C0=1 for "ST0 < src", C3=1 for equal, C2=1 for unordered; fnstsw ax puts C0 at bit 0 of ah, C2 at bit 2, C3 at bit 6):

# Address Instruction Meaning acdream
1 0050a3c4 test ah,1 after fcomp [0x795344] C0 alone → slidingAngle < 0checkSlide = true; else sliding_normal_valid = 0 TransitionTypes.cs:5192-5199
2 0050a502 test ah,0x41 / 0050a505 jne 0x50a515 C0|C3 → collisionAngle <= 0 → subtract arm; fall through (> 0) → call 0x509c50 :5246-5258diverges, AD-65
3 0050a5d3 test ah,5 + jp 0x50a6a8 after fcompp PF set ⇔ C0=C2 ⇔ (ordered) C0=0 ⇔ dist >= radius - 0.0002 → skip push-out :5297diverges in the threshold, AD-66
4 0050a5ed test ah,0x41 / jne 0x50a6a4 C0|C3 → radius <= abs(zDist) → skip :5302 radius > MathF.Abs(zDist)

Everything else lines up instruction-for-instruction:

  • No-contact-plane early return (0050a61c): if !checkSlide, returns the offset untouched and jumps past the safety block; else offset -= sliding_normal * slidingAngle (0050a624-0050a69e) and still skips the safety block. acdream :5202-5223 including the skip.
  • Crease order. 0050a412-0050a458 builds cross(contact_plane.N, sliding_normal) in that operand order ([esp+0x14] = sn.z*cpn.y - sn.y*cpn.z = cross(cpn, sn).x). acdream :5228 Vector3.Cross(ci.ContactPlane.Normal, ci.SlidingNormal) .
  • Degenerate-crease guard. 0050a45c call 0x452460 = AC1Legacy::Vector3::normalize_check_small; disassembled at 0x00452460 it computes len = sqrt(x²+y²+z²), compares against [0x79b6ac] = 0.0002f (raw 17b75139), returns 1 (and leaves the vector alone) when len < that, otherwise normalizes and returns 0. Retail then zeroes the offset on return-1. acdream :5233-5243 computes the length, compares slideLen < PhysicsGlobals.EPSILON (= 0.0002), zeroes on true, else divides by the length and dots — algebraically identical, same threshold, same constant .
  • Safety block gating contact_plane_is_water == 0 && contact_plane_cell_id != 0 (0050a569, 0050a577) :5285. Retail additionally converts through LandDefs::get_block_offset (0x0043E630, called at 0050a592) because its contact plane is cell-local; acdream's sphere is already global — a representational difference, not a behavioural one.
  • Push-out vector (0, 0, zDist) and SPHEREPATH::add_offset_to_check_pos (0x00509D10, called at 0050a612 with ecx = this+0x20) :5304.

Cross-check: ACE agrees with retail on both divergent points (references/ACE/Source/ACE.Server/Physics/Transition.cs:60-88 calls ContactPlane.SnapToPlane(ref offset) on the else arm and uses the bare globSphere.Radius in both the trigger and the numerator). So acdream is the outlier against both oracles, which is what AD-65/AD-66 now record.

1.2 Does retail project against collision_info.contact_plane, and who produces it?

Yes, and the producer set is broader than claimed — which strengthens rather than weakens the argument.

adjust_offset reads this->collision_info.contact_plane at edi+0x28c gated on contact_plane_valid at edi+0x288. It is called per sub-step from inside the step loop of CTransition::find_transitional_position (0x0050BDF0, call at 0050bf66, immediately followed by the WalkInterp = (i+1)/numSteps computation at 0050bfc2-0050bfe9 that identifies the loop body); the only other caller is CTransition::find_placement_pos (0x0050BA50, call at 0050bcfd). Two call sites total, byte-scanned across the whole .text for E8 rel32 targets.

Byte-scanning .text for calls to COLLISIONINFO::set_contact_plane (0x00509D80) gives nine producers:

0050ab37  CTransition::validate_transition +0xc7
0050acca  CTransition::validate_transition +0x25a
0050d1c7  OBJECTINFO::validate_walkable    +0x1b7
0050d2e1  OBJECTINFO::validate_walkable    +0x2d1
00536ecf  CSphere::step_sphere_down        +0x1af
00537db1  CSphere::intersects_sphere       +0x331
0053a5ee  BSPTREE::find_collisions         +0x1ae
0053aae2  CCylSphere::step_sphere_down     +0x132
0053b6b9  CCylSphere::intersects_sphere    +0x279

BSPTREE::find_collisions and both step_sphere_down variants are on the list, so the claim that retail's contact plane natively carries building and EnvCell geometry — the gap a terrain-only XY sample structurally cannot cover — is confirmed. Two nits, neither material: BSPTREE::step_sphere_down (0x0053A210) is not itself a setter (it reaches the plane through the CSphere/CCylSphere pair), and the claim omits intersects_sphere ×2 and the validate_* pair.

Corroborating the other half of the argument — that retail has no pre-sweep projection: CPhysicsObj::UpdatePositionInternal (0x00512C30, pc:280817) is CPartArray::Update → root-frame scale gated on transient_state & 2 (0x00512CA1; × m_scale when set, × 0 when clear) → PositionManager::adjust_offsetFrame::combineUpdatePhysicsInternalprocess_hooks. No plane, no normal, no dot product anywhere before the sweep.

1.3 Constants

Read as raw bytes from .rdata at the stated VAs:

VA Bytes Value
0x00795344 00000000 0.0f
0x007c6878 17b75139 0.00019999999494757503f
0x0079b6ac 17b75139 same 0.0002f (the normalize_check_small threshold)
0x007928c0 000000000000f03f 1.0 (double, snap_to_plane's reciprocal numerator)

1.4 AD-65 — the snap_to_plane substitution

Disassembly claim: CONFIRMED exactly. Trigonometric formula: CONFIRMED. Percentages: WRONG — see finding F1.

0050a4fa fcomp [0x795344] / 0050a502 test ah,0x41 / 0050a505 jne 0x50a515 are byte-for-byte as the row states, and the FPU reasoning is right: jne takes the SUBTRACT arm at 0x50a515 (which is literally result -= N * collisionAngle, spelled out at 0050a515-0050a565) when cAngle <= 0, and falls through to call 0x509c50 when cAngle > 0. 0x00509C50 is Plane::snap_to_plane per symbols.json, and disassembling it gives, after an early return when |N.z| <= 0.0002:

v.z = -(v.x*N.x + v.y*N.y) / N.z      ; v.x and v.y are never written

(the +D and -D terms at 0050a58f/0050c996 cancel exactly; ACE's PlaneExtensions.SnapToPlane writes the same cancelling pair). acdream's else arm at TransitionTypes.cs:5252-5258 is instead result -= N * collisionAngle, identical to the if arm — the row's core claim, confirmed.

Geometry, re-derived independently. Slope descending along +X at angle θ has outward normal N = (sinθ, 0, cosθ). For a horizontal step v = (d, 0, 0) downhill, v·N = d·sinθ > 0 → the snap_to_plane arm:

  • retail: (d, 0, -d·tanθ)XY preserved at d, along-plane speed d/cosθ;
  • acdream: (d·cos²θ, 0, -d·sinθ·cosθ)XY = d·cos²θ, along-plane speed d·cosθ.

So the XY ratio is cos²θ. The row's formula is right.

1.5 AD-66 — the safety push-out threshold

CONFIRMED, all four operand loads, verbatim.

0050a5c4  d9410c    fld    dword ptr [ecx+0xc]     ; bare radius
0050a5c7  d82578687c00  fsub dword ptr [0x7c6878]  ; - 0.0002f
0050a5cd  d9c1      fld st(1)                      ; dist
0050a5cf  ded9      fcompp                         ; dist  vs  radius - eps
...
0050a5dc  d8690c    fsubr  dword ptr [ecx+0xc]     ; radius - dist  (bare radius again)
0050a5df  d87608    fdiv   dword ptr [esi+8]       ; / contact_plane.N.z

Neither site multiplies by N.z. acdream substitutes naturalRestingDist = radius * ci.ContactPlane.Normal.Z in both places (TransitionTypes.cs:5295 and :5301), exactly as the row says, and the row is right that ACE has retail's form too — so "ACE and the published pseudocode have the original threshold" in the code comment does understate it. Filing an argued-but-unrecorded deviation is correct register hygiene.

1.6 Address / anchor precision audit

Every cited address re-checked as the construct claimed (this is the class of error that produced AP-150's mis-cite):

Citation Verified
CTransition::adjust_offset 0x0050a370 symbol + ret 8 at 0x0050a6c7
Plane::snap_to_plane 0x00509c50 symbol; body is the z-only solve
0050a4fa / 0050a502 / 0050a505 exact instructions as quoted
0050a5c4 / 0050a5c7 / 0050a5dc / 0050a5df exact instructions as quoted
0x795344 = 0.0f, 0x7c6878 = 0.0002f raw bytes as quoted
CTransition::find_transitional_position 0x0050bdf0 symbol; per-step call at 0050bf66
pc:272271272393 272271 is the adjust_offset signature line, 272393 the closing }exact
pc:271852 (snap_to_plane) exact signature line
old anchor pc:272296272346 "truncated" 272296 = float __return_1; (after the sliding-normal gate closes at 272292); 272346 = if (contact_plane_is_water == 0) (the safety block's first line). Both truncations real.

AD-65's methodological claim — that Binary Ninja "cannot be read for branch direction" — is accurate and correctly narrow. BN does render the snap_to_plane call plainly (pc:272322) and gets the arm order structurally right; what it cannot express is which FPU condition bits test ah,0x41 selects, which it emits as (*(uint8_t*)((char*)eax_4)[1] & 0x41) != 0. The disassembly was necessary and the row does not overclaim.


2. Is the deletion itself retail-faithful?

Yes, and more strongly than the commit argues.

  • The sweep genuinely runs for remotes: RuntimeRemotePhysicsUpdater.cs:414 calls _physics.Engine.ResolveWithTransition(preIntegratePos, postIntegratePos, …, body: rm.Body, …) and :457 assigns rm.Body.Position = resolveResult.Position unconditionally, so the sweep is authoritative over the composed root motion. The old row's justification ("remote bodies don't run a full local transition sweep") was indeed false, and the retirement row says so.
  • PhysicsEngine.SampleTerrainWalkable (PhysicsEngine.cs:1023) is a pure (worldX, worldY) landblock scan — Z-blind, cell-blind, statics-blind. The "wrong surface on a bridge/roof/dungeon ramp" claim is structural, not rhetorical.
  • Retail has no pre-sweep projection (§1.2). Deleting one is the retail direction regardless of what the measurement had shown.
  • The composition-idempotence argument holds: after v -= N·(v·N), dot(v, N) == 0, so a second projection against the same plane is a no-op — which is why the trajectory came out bit-identical, and why the deletion cannot regress the same-plane (terrain) case.

Residue check: no production caller of RemoteMotionCombiner.ComputeOffset remains (tests only), SampleTerrainNormal survives only in comments, and the parameter removal makes a one-site regression a compile error as claimed.


3. Findings

F1 — MEDIUM. AD-65's percentages are wrong by ~2×, and contradict its own formula and the project's own measurement

docs/architecture/retail-divergence-register.md, row AD-65:

acdream therefore descends slopes SLOWER than retail by cos^2(theta) in XY: 13% slow at 30 degrees, 29% at 45 degrees.

cos²(30°) = 0.75025% slow. cos²(45°) = 0.50050% slow. The quoted figures are 1 cos θ (13.4% and 29.3%), not 1 cos²θ; the row states the correct factor and then quantifies a different one.

This is not a matter of interpretation — the same push measured it. #331 (docs/ISSUES.md, added in 2223ed17) records a probe on the gradient-0.6 ramp (θ = 30.96°): the XY advance is 0.0735 m for a 0.1 m request. That is cos²(30.96°) = 0.7353, i.e. 26.5% slow — a direct empirical refutation of "13% at 30 degrees", sitting in a neighbouring file in the same commit series.

Consequence: AD-65 is filed as a lead for #269, and the number is exactly what a future reader will weigh when deciding whether the lead is worth chasing. Halving the magnitude makes a 50%-at-45° downhill speed loss look like a rounding-error feel issue. Fix the two percentages to 25% and 50% before this row is used for anything.

  • Retail: CTransition::adjust_offset 0x0050a370, arm select at 0050a505; Plane::snap_to_plane 0x00509c50.
  • acdream: src/AcDream.Core/Physics/TransitionTypes.cs:5252-5258.
  • Observable in game: a player or remote running downhill on a 45° face covers half the ground per second that retail does (25% less at 30°); on the same input the body's along-plane speed is d·cosθ where retail's is d/cosθ. Uphill is correct.

F2 — MEDIUM. "Verbatim / faithful port" is asserted about Transition.AdjustOffset in five places, and is false as of the very next commit

The change repeatedly certifies the port it is standing on:

  • src/AcDream.Runtime/Physics/RuntimeRemotePhysicsUpdater.cs:276 and :321 — "ported verbatim in Transition.AdjustOffset";
  • src/AcDream.Core/Physics/RemoteMotionCombiner.cs:46 — "acdream ports that verbatim";
  • tests/AcDream.Runtime.Tests/Physics/RuntimeRemoteSlopeProjectionTests.cs:11 — "acdream ports that faithfully";
  • the retired AD-10 register row — "runs acdream's verbatim port of CTransition::adjust_offset once per sub-step";
  • fe6ee877's commit message — same phrase.

One commit later, fb454b74 files two divergences inside that exact function. The register now simultaneously asserts that AdjustOffset is a verbatim port and that it substitutes a different operation on one of its three arms and a different constant in its safety block. A future maintainer grepping "verbatim" for a trustworthy reference implementation will be misled, and the retired AD-10 row — the permanent record — is the worst place for it.

Not a code defect; the deletion argument survives untouched (see F3 for why it in fact survives because of AD-65). But four comments and one register row should read "ported apart from AD-65 and AD-66" or cite them inline.

F3 — LOW/MEDIUM. The "measured redundant" evidence is contingent on AD-65, and the register does not say so

The bit-identical measurement is a consequence of the divergence filed the same day. acdream's away-plane arm is v -= N·(v·N)the same operation as the deleted pre-sweep projection — so the composition is idempotent and deleting one changes nothing. If AD-65 is ever fixed, the away-plane arm becomes snap_to_plane, which preserves XY; a surviving pre-sweep projection would then have shrunk XY to cos²θ before snap_to_plane locked it in, and snap_to_plane (being a no-op on an already-on-plane vector) would have had no way to recover it.

So the deletion is not merely safe — it is a prerequisite for AD-65's eventual fix, and the ordering (delete first, then fix AD-65) is the right one. That is a point in the change's favour, and it is missing from the record. The retired row reads "measured redundant" flat, which invites a future reader to conclude the pre-sweep layer was always a no-op on principle. Recommend one sentence in AD-65 and/or the retired AD-10 row noting the interaction.

Related, minor: the surviving measurement is downhill-only, because #331 made the uphill counterpart vacuous. The commit message and #331 are both candid about this; the register row is not, and simply says "30 ticks down a 31-degree ramp" — which is accurate but reads as a choice rather than as a constraint. No action required beyond awareness.

F4 — LOW. Malformed XML doc on ComposeOffset will hide the AD-10 note from tooling

src/AcDream.Core/Physics/RemoteMotionCombiner.cs:34-53: the summary closes at line 38, the AD-10 <para> block sits at document top level from line 40, and a second, unmatched </summary> appears at line 52. The project sets no GenerateDocumentationFile, so the compiler is silent — but IDE tooltips and any generated docs will show only the first paragraph and drop the retirement note, which is precisely the note a future maintainer of this method needs. Move the <para> inside the first </summary> and delete the second.

F5 — LOW. AD-65 and AD-66 cite files without lines

Both new rows name src/AcDream.Core/Physics/TransitionTypes.cs with a prose description of the block. Adjacent rows (AD-5, AD-12, AD-13, AD-62, AD-64) give file:line. The exact anchors are :5252-5258 (AD-65's else arm) and :5285-5310 (AD-66's safety block). In a 5,000-line file this matters.

F6 — informational. A foreign untracked file appeared in the worktree mid-review and must not be committed

tests/AcDream.Runtime.Tests/Physics/ZzReviewTrajectoryDump.cs (self-described "TEMPORARY reviewer probe (2026-08-06 AD-10 architecture review). Delete.", 13 test attributes) was not present at the start of this review and appeared at 09:49 during it — a concurrent review session writing into the same worktree. It was compiled into the Release build and inflated the raw suite count by 12. It is not part of this change and must be deleted before merge.


4. Bookkeeping audit

AD-10's retirement is earned by the code, not asserted. Positive evidence: SampleTerrainNormal is absent from the freshly built AcDream.Core.dll image; the terrainNormal parameter is gone from both ComposeOffset and ComputeOffset; both RuntimeRemotePhysicsUpdater fork branches are cleared; the two Core tests are deleted; nothing but comments references the removed API. The row follows house style — ~~AD-10~~, bold RETIRED 2026-08-06 by deletion, past tense, evidence inline, in the justification/risk columns, retail anchor retained and corrected — matching the AD-6 / AD-11 precedent. Removing the parameter rather than defaulting it to null is the right call and does make a one-site regression a compile error.

Three stale claims in the old row are recorded rather than dropped (the false "remotes don't run the sweep" justification, the "interpolation-active" mis-description of if (!interpolationOverwrote, and the roof clause dead since Bug B gated on OnWalkable). All three check out against the code.

AD-65 and AD-66 are honestly scoped. AD-65 explicitly says "Not justified — this is an unexamined substitution, not a decision", and explains why it is filed rather than fixed (it changes local-player feel and needs its own visual gate; folding it into a remote-movement change would put a local-player regression behind the wrong acceptance test). That reasoning is correct. AD-66 is scrupulous in the other direction: "Filed to make the deviation auditable, not to assert it is wrong", and it names the failure mode in both directions. Neither row claims more than the disassembly supports — except for F1's numbers.

AD-65 is correctly recorded as a lead, not a diagnosis, in bold, with "nothing here establishes causation" and "#269 still needs its live cdb A/B". It does not overreach into the exonerated area: it states explicitly that "#269's friction and jump chains are byte-exonerated and must not be re-audited; adjust_offset is a different function and is not covered by that do-not-retry". That is the correct boundary — adjust_offset was never part of the friction/jump byte-verification — and the row draws it itself rather than leaving a future reader to.

The #32 corrections are accurate. Both edited paragraphs were checked against the code:

  • The "even a corrected OnWalkable would need a real contact-plane-derived slide" paragraph is correctly marked superseded with an inverted premise — remotes do run the sweep, and on a steep roof bodyOnWalkableAtTickStart was false anyway, so the deleted sample never ran on #32's geometry and the roof slide was already contact-plane driven.
  • The dependency paragraph is correctly struck and replaced with "discharged rather than merely gated".
  • The "does not fix #32, and does not partially fix it" claim holds, and the commit message states it in exactly those words. #32's remote half closed at 204d0ae0; nothing here touches the local-player edge-slide or the three recorded gaps. The genuine improvement claimed — a remote on a walkable non-terrain surface now gets its own committed contact plane rather than the plane of the ground far below — follows directly from SampleTerrainWalkable being XY-only, and is correctly described as a case #32 never covered rather than as progress on #32.

#331 and #332 are honest filings. #331 records a probe result that invalidated a test that had passed, states severity UNKNOWN on purpose, lists five ruled-out hypotheses with the probe evidence for each, and names the single comparison that decides severity. #332 is scoped as an observation with an instantiation census rather than an inference, and records the reasoning trap (assembly placement ≠ reachability) that would otherwise have produced a vacuous headless gate. Both explicitly disclaim causation by AD-10, correctly.

Test-count reconciliation reproduces exactly. Raw full-suite result on the clean Release build was 11,208 passed / 4 skipped / 0 failed; the foreign probe file (F6) contributes 12 executed tests (--filter FullyQualifiedName!~ZzReviewTrajectoryDump → Runtime 1,232 → 1,220). 11,208 12 = 11,196 passed / 4 skipped / 0 failed, matching 886333a2's claim to the test. The +3 Runtime / 2 Core arithmetic is structurally verified too: RuntimeRemoteSlopeProjectionTests carries exactly three [Fact]s and the diff deletes exactly two Core tests.

Test honesty. RuntimeRemoteSlopeProjectionTests states in its own doc comment that short-circuiting Transition.AdjustOffset leaves it GREEN, names the reason (ValidateWalkable's push-out re-seats the sphere every sub-step), and forbids citing itself as a unit test of adjust_offset. The anti-vacuity guard (dz < -1.0 m) and the per-tick rather than start/end assertion are both the right shape. Expected values come from the fixture's own TerrainSurface.SampleZ, i.e. from geometry, not from a re-implementation of the projection formula — the weakness the two deleted Core tests had.


5. What was checked, so the PASS is auditable

  • PDB/EXE pairing (check_exe_pdb.py → MATCH) before any address work.
  • Full disassembly of CTransition::adjust_offset 0x0050a370-0x0050a6c7, arm by arm, against TransitionTypes.cs:5180-5322 line by line.
  • All four x87 condition-code tests decoded from fnstsw/test ah semantics.
  • Plane::snap_to_plane 0x00509c50 and Vector3::normalize_check_small 0x00452460 disassembled in full.
  • Four float/double constants read as raw bytes from .rdata.
  • Whole-.text E8 rel32 scan for callers of set_contact_plane (9 producers) and of adjust_offset (2 call sites), symbolised against symbols.json.
  • CPhysicsObj::UpdatePositionInternal 0x00512C30 read end to end to confirm retail has no pre-sweep projection.
  • All pc: anchors checked by line number in named-retail/acclient_2013_pseudo_c.txt, including the old truncated one.
  • ACE cross-check (Transition.cs, PlaneExtensions.cs) on both divergences.
  • RemoteMotionCombiner, RuntimeRemotePhysicsUpdater, PhysicsEngine.SampleTerrainWalkable, RemoteRampHarness, RuntimeRemoteSlopeProjectionTests read in full.
  • Orphan/residue greps for ComputeOffset, SampleTerrainNormal, terrainNormal.
  • 44 bin/obj directories deleted; clean Release build (0 errors); full suite (0 failures); staleness disproved by byte-searching the built DLLs.

No third retail divergence was found in AdjustOffset, no mis-cited address was found, and no claim in the four commits was found to be unsupported by the binary — apart from AD-65's two percentage figures (F1).