Fix false-green in DeckLip arrival check (R16) + pathfix handoff#65
Open
lrhodes404 wants to merge 30 commits into
Open
Fix false-green in DeckLip arrival check (R16) + pathfix handoff#65lrhodes404 wants to merge 30 commits into
lrhodes404 wants to merge 30 commits into
Conversation
… + add pathfix handoff The arrival predicate accepted a `[TRAVEL_LEG] complete reason=walk_arrived` message from the whole RecentChatMessages ring (no delta, no proximity), so a stale walk_arrived declared arrival at the tower BASE (z=24.8, ~29y below Frezza) and the test PASSED while the bot never climbed (R16: the screenshot shows the bot at the base). Fix: arrival now requires observed position near Frezza (dist2D<=6 / |dz|<=4 primary); a walk_arrived only counts when NEW since the post-teleport baseline AND within dist2D<=12 / |dz|<=6. With the fix the (infra-gated, CI-skipped) test is honestly RED, localizing the real blocker to caller-side base->climb consumption (smooth-path start-jitter cluster; semantic blocked=1.00 normal=0 before the first StepUp) on the now-clean 128-corner service route -- NOT the off-mesh interior_projection (the bot never reaches it). Probe-driven + 6-agent adversarially-verified diagnosis, live-validated on the vmangos stack. Turnkey recipe + revised target: docs/physics/PATHFIX_GRUNT_FREZZA_HANDOFF_2026-06-01.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…now climbs the OG zeppelin spiral Root cause of the DeckLip base stall: TravelTask.CanCompleteWalkLeg returned true unconditionally for a non-transport walk leg, so TryGetWalkLegArrival completed the leg on 2D distance <= 15y ALONE. Frezza (z=53.6) is ~14.5y due-south of the Grunt base (z=24), so the base is ~14.8y 2D from Frezza yet ~30y below it -> the leg false-completed at the base, exhausting the route and dumping the bot into the line-178 route-exhausted fallback (TryNavigateToward with the default STANDARD policy, which cannot drive the long climb). The bot then sat frozen at the base. Fix (arrival-VERIFICATION per R2/R3, NOT a route relaxation): add WalkLegVerticalArrivalTolerance = 6.0f (matches the transport vertical tolerance) and gate the non-transport CanCompleteWalkLeg branch on it. A walk leg now arrives only when within the 2D radius AND on roughly the same vertical layer. Validated: - Unit: new Update_TargetDirectlyAboveWithinHorizontalRadius_DoesNotCompleteWalkLegAtBase; full TravelTaskTests 15/15 green (transport-handoff completion tests unaffected). - Live (vmangos): the bot now climbs the spiral ramp z24->z42 (idx0->~60 of 128, each afford=StepUp, leg stays 0/1), vs previously stalling at the base. Next blocker (distinct, documented in the handoff UPDATE 2): a mid-climb client disconnect/reset at ~z42 on the upper spiral (likely vmangos movement validation), to be diagnosed via mmo-movement-diagnostics — NOT band-aided. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… 80%); isolate deck-lip physics blocker
Continues the DeckLip diagnosis. Three more live-isolated fixes peel the onion to the
original deck-lip problem:
1. TravelTask top-level arrival was ALSO vertical-blind: Update() completed on 3D distance
<= _arrivalRadius, so at z41 (~8y horizontal + ~12.5y BELOW Frezza = ~15y 3D) it popped
travel_complete 12.5y under the deck. Now requires horizontal proximity AND
verticalDelta <= WalkLegVerticalArrivalTolerance.
2. ActionDispatcher sameMapTravelArrivalTolerance 15f -> 5f (matches TravelTask.DefaultArrivalRadius).
15y let TravelTo arrive ~14y short / on the ramp ~6y below a deck target. 5y = actually
reach the target (NPC interaction range).
** BLAST RADIUS: affects EVERY same-map TravelTo (now must reach within 5y, not 15y).
Validate against the full long-pathing/LiveValidation suite before merging to main. **
3. DeckLip is SAME-MAP, so stop disabling FG packet hooks (the cross-map-only
DisableForegroundPacketHooksForCrossMapTransfers caused a mid-climb LoginScreen reset).
Result: the bot now climbs the spiral base (z24) -> deck-lip (z47.4, idx102/128 ~80%), every
segment afford=StepUp, no false completion, no disconnect. TravelTaskTests 15/15 green.
TRUE remaining blocker (isolated, deep): at z47 the bot stalled_near_waypoint and SLIDES BACK
to z41. Probing the final stretch from the live stall returns 30 corners ALL Walk/StepUp/Clear
(ZERO Blocked) up to Frezza on the deck -- so route + static physics say it is traversable, but
the LIVE continuous swept-capsule motion cannot sustain the steep deck-lip climb and slides back
(B3-class static-vs-swept divergence). That is a PhysicsEngine slope/step-up / movement-execution
issue -- NOT bake, NOT arrival, NOT route. Next: mmo-movement-diagnostics on the z47->53.6 climb.
Full recipe in docs/physics/PATHFIX_GRUNT_FREZZA_HANDOFF_2026-06-01.md UPDATE 3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…thPath route, not physics Verified the deck-lip waypoints rather than assuming a physics wall. Each segment is Walk/StepUp/Clear, but the SMOOTH sequence oscillates: probe shows the smooth Grunt->Frezza route has 16 DOWN segments / 5.7y backward climb (the deck-lip idx86-101 bounces z47->46.5->47 in a ~2y cluster), while the RAW (findStraightPath) route has 1 DOWN seg and is perfectly monotonic. So smoothPath densification introduces the jitter; the bake/raw path is clean. The bot follows the smooth corners, is steered backward/down, makes no net progress (stalled_near_waypoint), and slides back -> stuck-guard. Mechanism = native findSmoothPath (PathFinder.cpp): moveAlongSurface + getPolyHeight hopping the spiral's overlapping Z-layers (or 2y step overshooting the tight curve); the custom densification even densifies the -dz hops. Recommended native fix on the smoothPath OUTPUT (instrument first, then monotonic/ forward-progress guard or curvature-adaptive step) -- NOT bake, NOT physics, NOT a managed band-aid. Portable check added to the collision-contract: verify route VALIDITY (monotonicity), not just per-segment walkability. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A self-contained iterate-until-GREEN prompt for a Claude (Opus) orchestrator session/loop that marshals diverse agents to fix the OG zeppelin deck-lip route: Workflow fan-outs to propose + adversarially refute fix hypotheses across model lenses, codex:rescue for native PathFinder.cpp / MmapGen bake implementation + an independent GPT-5.x diagnosis, parallel sub-agents for reads, with Claude owning the probe, the R16 screenshot reads, the validation loop, and commits. Encodes the confirmed root cause (MmapGen polys merge across non-traversable spiral/step-up geometry -> smoothPath hops Z-layers -> oscillating deck-lip waypoints), the probe/live oracles, a vetted fix-candidate menu (walkableClimb-vs-step-up, deck-edge poly break, off-mesh, native smoothPath guard), the R13/freeze rules, R16, the commit policy (PR #65), and a hard stop condition. Supersedes the Codex-only draft. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The OG Orgrimmar zeppelin tower is a vertical spiral; native findSmoothPath fell into a period-2 limit cycle at the deck-lip (moveAlongSurface's fixed 2.0y step bouncing iterPos between two mutually-reachable corridor anchors A(z47)/B(z46) while fixupCorridor rewound the corridor), emitting a non-monotonic A<->B waypoint ping-pong (16 DOWN segs / 5.66y backward) that stalled the live bot. RAW findStraightPath over the IDENTICAL Detour corridor is monotonic (DOWN=1), so the defect is in the smoothing densification alone, not the bake or physics. Fix (Exports/Navigation/PathFinder.cpp::findSmoothPath): an emission guard with retroactive cycle suppression. The WALK is byte-unchanged (the 2.0y step is load-bearing for corridor drain + termination -- capping it starves consumption and spins to a 4095-corner truncation). Each iteration computes the remaining corridor-arc distance to target; a non-progress corner is buffered, then a SHORT buffered run (a benign path bend) is FLUSHED so its chord stays walkable while a LONG run (the limit cycle) is DISCARDED so the oscillation collapses. A hard iteration cap truncates+replans a non-escaping cycle. Validation: probe Grunt->Frezza smooth collapses 16 DOWN / 5.66y -> 4 DOWN / 1.05y, 0 Blocked, reaches Frezza; live DeckLip test now climbs MONOTONICALLY z24->z47.9 with no oscillation (R16 screenshots confirm bot on the upper ramp). Regression guard added: DeckLipRawPathContractTests.SmoothRouteDoesNotOscillate. The live test stays RED on a now-DISTINCT blocker (slide-back after the walk-leg completes at z47.9, currentSpeed=0); see handoff UPDATE 5. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… on the overlapping spiral Iteration-B localization (codex-cross-checked, code-verified). The deck-lip slide-back is a NATIVE swept-physics defect in Exports/Navigation/PhysicsEngine.cpp (StepV2 / CollisionStepWoW), not managed and not the static classifier (which says the ramp is fully climbable from z41 and z47.7 -- 0 Blocked). Root: drive-gap support loss -- when the leg false-completes at z47.9 and drive drops, the grounded- idle branch (PhysicsEngine.cpp:5988-5998) does a raw GetGroundZ that re-grounds the bot to a LOWER wrap of the overlapping spiral (same XY stacks z24/28/37/47/53), and CollisionStepWoW then re-enters from the corrupted lower-layer support and stalls (blocked=1.00 / no wall / no normal = semantic zero-progress, the native default). Fix surface = native ground-stick on walkable slopes (prefer prevGroundZ support, guard the pre-sweep snap), NOT the managed arrival radius. Iteration C: confirm idle-snap-down vs FALLINGFAR-fall with a live per-tick physics trace before editing this load-bearing engine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… for the slide-back physics fix Scoped how to capture the confirming per-tick physics trace before editing the load-bearing FG swept engine. Findings: native PHYS logging exists (VMAP_PHYS_LOG_* env, std::cout sink) but the FG bot's native stdout is NOT captured live; the managed MovementController already records a full per-tick PhysicsFrameRecord (pos/rawZ/groundZ/ prevGroundZ/falling/flags/blocked) but only when IsRecording and never dumps it, and it lives in the FG-bot process (unreachable from the test). Recommended trace path = an env-gated file-dump added to the FG bot (managed; no bitness). WoWSharpClient is AnyCPU (loads Navigation.dll at FG-host bitness); build both x64+x86 for any native physics change. Root + fix surface unchanged (UPDATE 6): native ground-stick in the grounded-idle branch (prefer prevGroundZ support, don't snap to a lower spiral wrap), NOT the arrival radius. Iteration-D recipe + owner status framing recorded: the loop's explicit smooth- oscillation mission is fixed+committed (6ec1355); the slide-back is a deeper multi-cycle FG-physics effort best run as a focused session. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…vmesh-first) The bot should follow accurate Detour paths, not gate/deflect movement on a physics wall-contact signal. For the ForegroundBotRunner that signal was never even real -- the FG ObjectManager never overrode PhysicsHitWall/BlockedFraction/ WallNormal2D, so the nav was reading the IObjectManager DEFAULTS (false / 1.0 / (0,0)) every tick. Remove the whole run-time crutch chain (R18 full removal): native swept output -> MovementController.LastHitWall/LastBlockedFraction/ LastWallNormal -> IObjectManager.Physics* props -> NavigationPath.GetNextWaypoint wall-avoidance (geometric deflection + wall-stuck force-repath + avoidance waypoint). Also delete PhysicsStateHelper, the [NAV_EXEC] physics-read diagnostic, the PhysicsFrameRecord wall fields + DiagnosticsRecorder CSV columns, and the wall-specific tests. The CORE Detour path-following in GetNextWaypoint is untouched: next-waypoint resolution, advance-on-reach, recalc-on-exhaustion, direct fallback, transport hold, and the non-wall stalled-near-waypoint replan all preserved. The removed block only ran under `if(physicsHitWall)` (now permanently absent), so it was dead input, not lost capability. KEPT (scaffolding, to be removed after the navmesh is made accurate): the plan-time swept-physics corridor-walkability validation (PathfindingClient. IsBlockingWallContact + PathfindingService Navigation.cs segment validation) and the native PhysicsOutput fields. These guard against committing to a Detour corridor that is walkable on the mesh but not in geometry -- i.e. they compensate for navmesh inaccuracy, so they become redundant once Recast/mmaps are accurate. The client-side strict Compatible=!hitWall (PathfindingClient.cs:400) is the remnant to remove first at that point. Verified: managed build green; NavigationPath/TravelTask/factory tests 164 pass / 0 fail; 3-lens adversarial review clean (path-follow + completeness), no orphans. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(proper LAYERS partitioning) Owner direction reset: the FG bot drives the ORIGINAL WoW.exe client, so the run- time physics-wall-feedback the nav was gating on (a dummy IObjectManager default for FG) is a crutch over an inaccurate navmesh -- removed in 6fa84c4. The real deck-lip fix is the Recast bake: the OG tower is a vertical spiral (same XY stacks z24/28/37/47/53) and Recast's single-layer heightfield merges the stacked surfaces (~64 polys/>=7 wraps survive at one XY), so Detour string-pulls/smooths across non-traversable wraps. tools/MmapGen/config.json tile 4029 is a ~190-line graveyard of per-coordinate cull band-aids + an over-lowered climb (0.2 vs harvested 1.8) that never collapsed the stack. Verified config-only fix: per-tile partitionType:layers (rcBuildLayerRegions, fully plumbed) -- Recast's purpose-built tool for stacked surfaces -- retried CLEAN (the prior layers attempt failed only by coupling simplification/maxVertsPerPoly churn), plus retire the cull band-aids + restore harvested climb. Full turnkey recipe + probe/no-regression validation gate + the 4029 poly-ID-churn rebaseline + the post-accuracy plan-time-validation removal recorded. Honesty: the UPDATE 6-7 slide-back is a downstream consumer of the bad mesh; the layered bake removes that surface (complementary), and any PhysicsEngine change must come from decompiled WoW.exe per the parity rule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(layers) for the OG spiral Per owner directive (navmesh-first, no band-aids): the OG zeppelin spiral was fixed by ~600 occurrences of bespoke per-coordinate culls/anchor hacks in TileWorker.cpp (~10,250 lines) + ~42 hardcoded-coordinate config entries + Recast contour-simplify anchor overrides -- none of which collapsed the stacked-wrap mesh. Remove ALL of it (R18 full removal): the entire anonymous-namespace cull subsystem (postDetourCull*/preRegionCull*/preMedianCull*/prePoly*/preRasterizeCreate* / anchor-coord + route-target lists / anchor-stage manifest+diagnostics), reverting RecastContour.cpp to upstream (drop rcSetContourSimplifyAnchorOverrides + the seed helpers) and Recast.h (drop rcAnchorContourSimplifyOverride). config.json: drop every band-aid key from every tile; tile 4029 is now clean -- cs/tileSize + partitionType:layers (rcBuildLayerRegions, Recast's purpose-built tool for vertically-stacked surfaces) and the agentMaxClimb overrides deleted (restores harvested 1.8/1.2). TileWorker.cpp 12210 -> 1961 lines; cull/anchor refs 1846 -> 0; config band-aids 42 -> 0. MmapGen.exe rebuilt clean (966KB -> 584KB). Core Recast pipeline (rasterize->filter->compact->regions->contours->polymesh->detail->Detour), slope/area classification, climb derivation, off-mesh handling, and standard config knobs preserved untouched. Validated (rebaked tile 40,29 with layers + probe): Grunt#1->Frezza RAW 52 segs / DOWN=3 / 0 Blocked / reaches Frezza, SMOOTH 96 segs / DOWN=4 / 0 Blocked / reaches Frezza -- a routable deck-lip with zero band-aids. Next: full-map rebake + og-zeppelin no-regression + revert the iter-A smoothPath emission guard (also a band-aid) to confirm the bake alone yields clean smooth paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The deck-lip fix is the accurate Recast bake, not the consumer-side band-aids.
This lands the two remaining pieces of the UPDATE-8 navmesh-first pivot.
1. Full-world rebake was a silent no-op. bake-all-maps.ps1 ("regenerate ALL
tiles") completed in 0.9s writing ZERO .mmtile, so the cull/anchor removal
never reached the world. Root cause: MapBuilder::buildMap never set
TileInfo.m_forceRebuild, so buildTile hit `!forceRebuild && shouldSkipTile()`
and skipped all 786 existing tiles -- shouldSkipTile only rejects on
magic/dtVersion/mmapVersion, so a generation-LOGIC change (cull removal,
which does not bump the version) is silently swallowed by the incremental
skip. Fix: explicit --rebuild flag (generator.cpp -> MapBuilder::SetRebuildAll
-> buildMap propagates to TileInfo.m_forceRebuild); bake-all-maps.ps1 passes
it. Incremental skip stays the default for quick `MmapGen.exe <map>` dev
bakes. processQueuedTiles also now drains gracefully (queue.Cancel() +
WaitCompletion) instead of m_cancel.store(true) so in-flight builds finish.
Verified: map-1 rebake 786/786 tiles fresh, 335.7s, 866MB->671MB (-22%, the
culls were inflating poly counts).
2. Removed the iter-A findSmoothPath emission guard (78 lines, R18 full
removal). It suppressed a 16-DOWN/5.66y spiral limit cycle at the deck-lip;
with the accurate LAYERS-partitioned bake that cycle never forms. Re-probed
guard-free: RAW DOWN=3 / SMOOTH DOWN=6, 0 Blocked, reaches Frezza z53.63 --
identical to with-guard. The guard was masking bake inaccuracy.
No-regression: deck-lip RAW/SMOOTH reach Frezza 0-Blocked; OG-zeppelin manifest
5/5 routes resolve (clean=0 step=5 blocked=0 error=0). DeckLipRawPathContract
thresholds (DOWN<=8, backwardZ<=3.0, finalZ>=50) still hold without the guard.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…calc loop pins bot at base wp1 Live DeckLipClimbFromGruntToLiteralFrezza on the rebaked world is RED, but the diag + screenshots (R16) localize the failure AWAY from the navmesh: the live service returns the same clean 96-corner 0-Blocked Grunt->Frezza route the probe does. The bot stalls at base waypoint 1 (max idx reached this run = 1, player z pinned 23.7-24.0) in a stall-recalc starvation loop: reach wp1 -> stalled_near_ waypoint force-recalc resets currentIndex -> re-target wp1 -> repeat (8x), never attempting the climb to wp2+. AdvanceReachableWaypoints/stall machinery is intact (the wall-feedback removal only deleted the physicsHitWall-gated branch FG never entered), so the trigger is the new --rebuild path geometry tripping the stall detector at the base. Next: isolate rebake-vs-stall-logic, fix recalc to preserve corridor progress (not reset to base), parity-correct FG step-up if needed -- no wall-feedback crutch, no arrival relaxation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l steeper
The generator marked 52-60deg slopes as walkable NAV_GROUND (AREA_STEEP_SLOPE,
10x cost), so the player pathfinder routed the bot over surfaces the WoW client
cannot walk -- e.g. the OG-tower route diving z61->z8 down ~55deg slopes into a
harbor dead-end (the bot would actually slide/fall those, not walk them). A
non-walkable slope is non-walkable in BOTH directions (the client slides; it
never "walks down" a steep face), so these polys must be absent from the player
mesh, not penalized-walkable.
Fix: set the walkable cutoff to the harvested WoW.exe limit -- cos(50deg)=0.642788
@ VA 0x0080DFFC ("slopes steeper than 50deg non-walkable"). playerClimbLimit
52->50deg; walkableSlopeAngle/VMaps 60->50deg. The two thresholds now coincide so
the AREA_STEEP_SLOPE walkable band collapses: >50deg terrain is nulled at raster
(stock rcMarkWalkableTriangles behavior), like vanilla vmangos' player mesh. No
runtime NAV_STEEP_SLOPES exclude (that path exploded Detour A* and was reverted) --
the slopes are simply gone from the mesh.
Validated (map 1 rebake): deck-lip Grunt->Frezza climb survives clean (RAW reaches
z53.63, biggest drop -0.4y; the legit spiral ramp is <=50deg). Mesh dropped
671MB->368MB (-45%): walls, cliffs, and steep slide-faces that were wrongly
walkable. og-zeppelin probe: deck-lip + boarding routes still resolve; the two
z61-start "descent" routes (ClimbOrgrimmarTowerToFrezza, FlightMasterDescentControl)
now correctly classify Blocked -- they were false slide-surfaces and need real
walkable routes or off-mesh links (zeppelin/flightpath), not >50deg ramps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ive base wedge The deck-lip tile (4029) used walkableErosionRadius=0.2y -- a band-aid that decoupled the navmesh erosion from the Tauren collision capsule (radius 1.0247y) to preserve thin top-deck slabs. Side effect: the walkable surface hugged to within 0.2y of the OG tower-base awning walls (46 vertical VMAP walls, walkable=0, sit 0.5y off the route), so the bot's 1.02y capsule CLIPPED those walls and the live FG bot wedged at the base -- pinned z23.8, max waypoint idx=1, never climbed. Fix: erode by the full capsule radius (1.0247y) so the navmesh stays >1y off the walls. The "thin slabs would break" fear that justified the band-aid does not hold at 1.02y erosion (the old failure was at 0.0y, a different regime). Live-confirmed 2026-06-03 on the rebaked tile: the bot now climbs z24 -> z47.7 (68 waypoints up the spiral; screenshot shows it on the tower looking down at the harbor), where the remaining blocker is the original deck-lip final step onto Frezza's deck (z47.7 -> z53.6). No route regression: Grunt->Frezza RAW reaches z53.63 (59 segs) and the boarding/deck routes (OgApproach/OgFrezza/DeckLipStall) all still resolve 0-blocked. Tile 5041KB -> 2749KB (near-wall mesh correctly gone). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…agnosis) Screenshot-based diagnosis was unreliable (mislabeled a mid-climb ramp position as "ramming the center pole" and invented a harbor view). Replace it with machine-readable per-tick telemetry on the long-travel drive: position, current facing vs bearing-to-waypoint (hdgErr), target waypoint + dist2D/wpDz, and actual displacement since last tick (moved2D/movedZ). Gated to the same long-travel trace flag as the other NAV_EXEC lines. This classifies movement failures from data, no images: moved2D~0 + small hdgErr -> blocked/colliding (x-ref offline navmesh wall/headroom) large hdgErr -> facing/turn problem movedZ<0 while grounded -> slide-back First use proved its worth on the OG deck-lip: the trace shows the bot climbs the spiral SMOOTHLY z24->z47.36 (moved2D~1.2/tick, movedZ~+0.5, small hdgErr -- the navmesh is reliable after the 50deg + full-erosion fixes), then the [TICK#] z goes z47.0 -> z41.7 -- a ~5y slide-back at the deck-lip. So the remaining blocker is the native grounded-idle re-grounding onto a lower spiral wrap (UPDATE 6), NOT a navmesh wedge and NOT the center pole. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng footprint-trim fix Tile 4029 runs cs=0.1 but inherited the global detailSampleDist=1.6/MaxError=0.5 (one detail sample per ~16 cells) -- a real cs/detail mismatch. Set 0.3/0.2 so rcBuildPolyMeshDetail conforms to the fine ramp/lip surface. This is a genuine accuracy fix but does NOT solve the deck-lip fall. Live-confirmed via [NAV_TELEM]: bot still climbs z24->z47.36 then falls to z41. Workflow + probes root-caused it: the navmesh lip poly cantilevers ~1.3y past the real floor edge (y=-4652.0) over an 8y inter-wrap void; the failed waypoint sits over the void. The detail mesh refines Z WITHIN the poly footprint -- it cannot trim the over-extended FOOTPRINT, which is what the bot walks off. Remaining fix (pinned in _4029_README_detail): trim the footprint by nulling the overhanging lip cells in filterLedgeSpans. They survive because mixedAreaUsesTerrain Climb=true holds the 1.8y terrain climb at the model-decorated deck edge, so the ~1.5y drop to the SEPARATE lower spiral wrap reads as a climbable downhill neighbor rather than a ledge-over-void (TileWorker.cpp:918-927). Needs a surgical change that distinguishes overhang-over-distinct-lower-layer from a continuous ramp/dock -- flipping the band-aids blindly risks both the legitimate 1.25y ramp->deck link and the dock/boarding cells. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…osion (tile 4029) The live FG test DeckLipClimbFromGruntToLiteralFrezza fell off the z47 spiral deck-lip into the inter-wrap void (landing z~41.7) for weeks. Root-caused with the per-stage compact-span CSV: the supported inner ramp floor at the lip dies at the EROSION stage (X1345.6/Y-4651..-4652: 394->152 walkable spans), NOT at filterLedgeSpans (rasterize==filterLedge there) and NOT at region/contour (regions==median==erode). The full 1.0247y Tauren-capsule erosion bites ~1.1y inward from the deck-edge riser/wall and wipes the narrow supported floor, leaving only the wider UNSUPPORTED cantilever; Detour then hugs that cantilever out over the void and the live capsule drops. Base (z24, awning-wall clip) needs the full radius while the z47 lip needs less -- same tile, so a single tile-wide radius cannot satisfy both. Add erodeWalkableAreaZBanded(): byte-identical to rcErodeWalkableArea's distance transform, but the final null pass picks a per-span erosion radius by world Z. Per-tile JSON-gated (erosionBandRadius + erosionBandMinZ/MaxZ); absent => stock rcErodeWalkableArea, so every other tile/map is byte-identical (no flag rot). Tile 4029: band z45-51 at radius 0.4y. Recovers the supported lip floor up to the real edge y~-4652 and widens the corridor ~0.5-1y -> ~2y. The z24 base and z53 Frezza deck/dock cells stay outside the band at full 1.0247y erosion. Live-verified 2/2: bot climbs z24->z47->~z51 on the deck, NO fall (fallTime=0, no movedZ<0 collapse at z47), test GREEN. Probe gates hold: Grunt->Frezza --detour-resolve + --smooth reach z>=53.6 with 0 Blocked; og-zeppelin dock/ boarding routes unchanged from baseline; tile ~3.3MB, no 16-bit vertex abort. Residual ~7-8y to Frezza's literal spawn is the separate pre-existing deck-lip 1.75y step-up, not the fall. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…DISABLED) NEGATIVE RESULT, not a validated fix. Bake is byte-identical to 545a782 (navCullBoxesWow empty); the live test still fails. Records this session's diagnosis so the next iteration starts from it. Findings (see docs/DECKLIP_ARRIVAL_DIAGNOSIS_HANDOFF.md): - The under-deck ramp tongue at the stall (1337.56,-4650.75,50.47) is REAL, well-supported, gently-sloped WMO floor (inst 234682). Per-stage compact-span CSV proves it passes the slope test, filterLedgeSpans, low-height AND erosion; it is interior-connected (~6-7y wide). No standard Recast filter rejects it, so the thin-slab-that-should-be-filtered hypothesis is refuted. - Added cullWalkableCompactSpansInBoxes (TileWorker.cpp): tile-scoped, JSON-gated (navCullBoxesWow) post-erosion+median walkable-span excision. With the box [1330,-4658,48.7,1339.3,-4645,52.0] it removes the tongue poly and ALL 4 probe gates pass (poly gone, Grunt to Frezza raw+smooth reach z53.63 0-blocked via the NE junction, dock routes baseline clean=0/step=3/blocked=2, tile 3.27MB). - BUT it REGRESSES the live FG test 2/2: the tongue IS the live bot's ascent route (it climbs region-11 westward onto it to z50.5); removing it makes the live NavigationPath cliff-reroute walk the bot OFF the ramp at z46 (freefall to z41) instead of taking the clean NE route. Mechanism left INERT (empty box) pending a fix that first makes the NE-junction to deck transition live-traversable (the real blocker the live path avoids). Also commits the honest tightened arrival gate (deck-Z required) in LongPathingTests.cs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eaction Doc-only. No bake/tile change (still 545a782-equivalent + 89f5744 inert cull). Iter-2 diagnosis (docs/DECKLIP_ARRIVAL_DIAGNOSIS_HANDOFF.md): - Probe --detour-resolve --smooth from the z47.5 hand-off point (1345.4,-4652.6, 47.5) to Frezza = 28 segs, 0 Blocked, stays on the corridor (min X at z49-52 = 1339.97, never the tongue), climbs the NE junction to the deck (z54.06) and walks to Frezza (z53.63). The navmesh path is correct from EVERY start point. - Live trace: single leg; walk-nav follows the 95-corner path correctly to idx~68 (z47.5-48.3, X1344-1348), then all NAV/TRAVEL logging stops ~4.2s while the bot drifts to the tongue (1337.6,-4650.8,50.5). No existing log captures the drift. - Mechanism is the consumer (NavigationPath.GetNextWaypoint ResolveDirectFallback + TryReplanFromNearVerticalLayerMismatch promoting a waypoint toward Frezza/west) reacting to local geometry; at the stall the path recalcs to waypointCount=1. - Bake<->consumer bridge: the destination-ward promotion is suppressed only if IsUphillLayerProgression && PreservesWalkableCorridor (= local-physics Z-delta<=5 && collision-support && IsSegmentWideEnoughForCharacter && HasWalkableNavmeshSamples) -- all navmesh-determined, so a tile-scoped corridor refinement near z48-52 is the legit bake lever, without touching the consumer. - Iter 3 = instrument the drift window (temp diagnostic), pin the failing check, then refine the bake. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Doc-only (temporary DECKLIP_DIAG instrumentation already reverted; tree clean). Irrefutable live trace (TravelTask.ExecuteWalkLeg + legs-exhausted final approach): - walk_arrived fires at pos=(1344.4,-4653.7,48.0): dist2D=13.96 (<=15) and vDelta=5.62 (<=6) -> arrived=True (prior tick z47.1/vDelta=6.50 was False). The walk leg arrives ~14y short of Frezza and 5.6y below the deck. - Then 93 ticks of the legs-exhausted same-map branch TryNavigateToward(target) (Standard policy, no NAV_EXEC -> explains the log silence at z47.5) drift the bot west+down from (1344.3,-4653.7,48.0) to (1337.4,-4649.4,41.2). Root cause: WalkLegArrivalRadius=15 + WalkLegVerticalArrivalTolerance=6 complete the navmesh-following walk leg 5.6y BELOW the deck; the Standard final approach then drives straight at Frezza's XY onto the under-deck tongue (stall) or off the ramp (fall). This is pure distance, NOT navmesh-sampled -> no bake change can prevent it. The navmesh path is correct (iter 2). The fix is necessarily a CONSUMER change (deck-tier-aware arrival / multi-leg route / LongTravel final approach), which the mission forbids -- needs the user to decide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lets an agent inspect a baked MmapGen --debug navmesh OBJ without RecastDemo: flood-fills poly connectivity into disjoint walkable islands, reports whether query points (e.g. lip + deck) share a component + nearest-approach gap, and renders top-down (height + component colored) and elevation (X-Z) PNGs. Built to give agent-side holistic navmesh inspection. It immediately corrected a prior analysis error: it confirmed the OG zeppelin lip, deck, and NE-junction are ONE connected component (lip-to-deck IS walkable via the NE-junction spiral), not the two-disjoint-islands a region-label-based analysis had claimed. Requires matplotlib+numpy. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ull path LongPathingTests.DeckLipClimbFromGruntToLiteralFrezza is now GREEN (live-verified 3/3: bot climbs the OG zeppelin spiral to Frezza's deck at z53.54, ~4.3-4.7y away, fallTime=0; R16 screenshot confirms it standing on the deck). Root cause (NOT the bake -- the navmesh connects lip->deck via the NE-junction spiral, confirmed by tools/scripts/navmesh_view.py connectivity flood-fill + two FindPath methods). TravelTask's plain walk-leg arrival fired on 2D-proximity to the goal while the bot was still below the deck: at z48 the bot is within WalkLegArrivalRadius=15y horizontally AND WalkLegVerticalArrivalTolerance=6y vertically of Frezza, so the leg "arrived" ~14y short and 5.6y below the deck and handed off to the Standard-policy close-range approach, which drove straight at Frezza's XY (west) into the deck-overhang dead-end (stall z50.5 / fall z41). I.e. the bot "got close and took a shortcut" instead of walking the full path up. Fix (Exports/BotRunner/Tasks/Travel/TravelTask.cs): - WalkLegArrivalRadius 15 -> 5: the navmesh-following leg drives all the way onto the deck to near Frezza before handing off, leaving only a short on-tier step (a bisect proved this is load-bearing: vert-alone passed the flag but the bot fell off the deck edge afterward). - WalkLegVerticalArrivalTolerance 6 -> 2: a plain walk leg only "arrives" on the destination's tier, never on the lip/tongue ~5.6y below the deck (refines the 2026-06-01 vertical-tier guard; cf. the 1.5y same-deck-tier boarding tolerance). Consumer-side only: no bake/navmesh change, no off-mesh link, no physics step-up-tolerance change. The committed Z-banded erosion fall-fix and the tightened test gate are kept. NOTE: these constants are global to walk legs -- the change makes ALL walk legs follow the path closer before the close-range handoff (the intended "walk all the way to the waypoint" behavior). Resolution recorded in docs/DECKLIP_ARRIVAL_DIAGNOSIS_HANDOFF.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n only Follow-up hardening of 710ab3e. That commit tightened the SHARED WalkLegArrivalRadius 15->5, which unintentionally also tightened transport-handoff detection (WalkLegHandsOffToTransport), flight-master approach (ExecuteFlightPathLeg), and transport/elevator EXIT arrival (HasReachedTransportExit) -- a latent regression risk for boarding/flight flows. Split it: WalkLegArrivalRadius is restored to 15y (used by the transport/flight/exit paths, behavior unchanged), and a new WalkLegFinalArrivalRadius=5y is used ONLY by GetWalkLegArrivalRadius (plain non-transport walk-leg completion -- the OG zeppelin deck-lip case). WalkLegVerticalArrivalTolerance stays 2y (already scoped to non-transport completion via CanCompleteWalkLeg). Re-verified the DeckLip live test stays GREEN with the scoped change (2/2 clean; 03-final z53.54, ~4.6y from Frezza, fallTime=0, R16 screenshot shows bot on the deck) -- 6/6 total across the unscoped + scoped versions. Transport/flight/exit arrival detection is now unaffected by the fix. Resolution updated in docs/DECKLIP_ARRIVAL_DIAGNOSIS_HANDOFF.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tile-scoped low-headroom preservation for the Orgrimmar zeppelin deck-lip beam treads. The new JSON-gated boxes keep the beam spans from being deleted by full standing-clearance filtering, restore compact links in that same box, and apply a separate no-erosion box to the upper treads while leaving the existing z[45,51] erosion fall-fix intact. Validation: - tools/MmapGen/build-mmapgen.ps1 (with DOTNET_ROOT=E:\dotnet8) - debug bake map 1 tile 40,29 to D:\wwow-bot\test-data, tile size 3,284,612 bytes - navmesh_view.py: final crop renders 511 faces; lip/deck/upper-beam samples share component c33 - PathPhysicsProbe Grunt->Frezza --detour-resolve: 59 segments, 0 Blocked, ends at z=53.63 - PathPhysicsProbe Grunt->Frezza --detour-resolve --smooth: 94 segments, 0 Blocked, ends at z=53.63 - probe-routes.ps1 og-zeppelin: baseline summary clean=0 step=3 blocked=2 error=0 - control tile 40,30 rebake byte-identical before/after: 00DC53B8B0ABE7979F42C5D2FC5AB0D5250FF563C043858E1AF0F120B7F81378 - LongPathingTests.DeckLipClimbFromGruntToLiteralFrezza: Passed; final snapshot (1334.34,-4646.44,53.54), fallTime=0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DeckLipClimbFromGruntToLiteralFrezzawas passing while the bot stood at the tower base (z=24.8, ~29y below Frezza) — a false green. The arrival predicate accepted a stale[TRAVEL_LEG] complete reason=walk_arrivedmessage from the wholeRecentChatMessagesring (no delta, no proximity). R16 screenshot confirmed the bot never climbed.Fix
Arrival now requires observed position near Frezza (dist2D<=6 / |dz|<=4 primary); a
walk_arrivedonly counts when NEW since the post-teleport baseline AND within dist2D<=12 / |dz|<=6. The test is[SkippableFact]+RequiresInfrastructure+ gated onWWOW_DECKLIP_DIRECT_FREZZA_TEST=1, so it skips in CI — this makes it honest when run live.Diagnosis (probe-driven + 6-agent verified + live-validated on vmangos)
blockedReason=none) for Grunt#1->Frezza — bake + runtime physics agree; the 2026-05-27 exterior/interior_projection:98route no longer reproduces.blocked=1.00 normal=0before the first StepUp) — NOT the off-meshinterior_projection(the bot never reaches it).Turnkey recipe + revised target:
docs/physics/PATHFIX_GRUNT_FREZZA_HANDOFF_2026-06-01.md. Cross-game lesson L72 + collision-contract spec landed in PCECore.🤖 Generated with Claude Code