# Code review: NEO-11 client path-follow (`NEO-11-client-path-follow`)

**Date:** 2026-04-05  
**Scope:** Branch `NEO-11-client-path-follow` vs `origin/main` (full NEO-11 slice: client nav, wiring, docs, small server remark).  
**Base:** `origin/main`

**Follow-up:** Design and docs were aligned after the initial review; blocking items and suggestions below are **done** unless marked otherwise.

## Verdict

**Approve** — original **Request changes** (plan/README vs obstacle wording) and review **suggestions** 1–3 are **resolved** in follow-up commits. Optional **nit** (rename `DESCEND_GOAL_Y_MARGIN`) remains open.

## Summary

The branch adds **`NavigationRegion3D`** / **`NavigationAgent3D`**, sync nav bake in **`main.gd`**, boot snap vs post-move nav goal via **`PositionAuthorityClient`**’s second signal argument, and horizontal path-follow in **`player.gd`**. **`ground_pick.gd`** gains stepped walkable picking for steep surfaces. Server change is documentation-only on **`MoveCommandValidation`** (vertical step remark).

**`player.gd`** intentionally skips nav waypoints when **`_auth_walk_goal.y < global_position.y - DESCEND_GOAL_Y_MARGIN`**, so for typical picks (floor **Y** vs mid-capsule origin) the client often **bee-lines in xz** toward the goal. That matches the **locked prototype tradeoff** (smooth bumps; multi-click around obstacles when needed).

**Idle optimization:** skipping **`move_and_slide()`** when there is no walk goal, velocity is zero, and **`is_on_floor()`** is a reasonable jitter mitigation; residual vibration is tracked in **[NEO-14](https://linear.app/neon-sprawl/issue/NEO-14)** (Tech Debt).

## Documentation checked

| Document | Result (at closure) |
|----------|---------------------|
| `docs/plans/NEO-11-implementation-plan.md` | **Matches** after **Locked — prototype movement tradeoff**, updated AC, tests, and **NEO-14** link. |
| `docs/decomposition/modules/E1_M1_InputAndMovementRuntime.md` | **Matches** — snapshot notes single-click obstacle detours not guaranteed. |
| `docs/decomposition/modules/client_server_authority.md` | **Matches** — server owns **`PositionState`**; client presentation path valid. |
| `docs/decomposition/modules/module_dependency_register.md` / `documentation_and_implementation_alignment.md` | **N/A** deep diff. |
| `client/README.md` | **Matches** — tradeoff, manual steps, **Known issue** + **NEO-14** link. |
| `server/README.md` | **Matches** — client nav presentation; detours not guaranteed on one click. |

## Blocking issues

**All resolved.**

1. ~~**Plan and README vs behavior:**~~ **Done.** Plan and **`client/README.md`** now state the **locked tradeoff** (descend bypass → xz bee-line; navmesh detours not guaranteed on one click; multi-click OK). AC checklist and manual QA updated accordingly.

## Suggestions

**All done.**

1. ~~**`DESCEND_GOAL_Y_MARGIN`:**~~ **Done.** Comment added in `client/scripts/player.gd` (surface pick Y vs mid-capsule; bumps vs obstacles).
2. ~~**`_skip_move_when_idle_on_floor`:**~~ **Done.** Doc comment above the helper (`is_on_floor()` / last `move_and_slide()`; static floors).
3. ~~**NEO-14:**~~ **Done.** Out of NEO-11 scope in plan; **[NEO-14](https://linear.app/neon-sprawl/issue/NEO-14)** linked from **`NEO-11-implementation-plan.md`** and **`client/README.md`**.

## Nits

- **Nit (optional):** Consider renaming **`DESCEND_GOAL_Y_MARGIN`** to something that signals “auth pick Y vs body origin” to reduce future “why do we always bee-line?” confusion. **Not done** — purely optional.

## Verification

- `cd server/NeonSprawl.Server && dotnet test` (no logic change expected, sanity).
- Godot **F5** with server: boot snap; click floor; bump flow; gray **Obstacle** may need **multiple clicks** per docs.
- Confirm NEO-10 reject targets still show rejection UX (`reasonCode` / label).
- `gdlint` / `gdformat` on touched GDScript if CI does not already run on the branch.
