---
created: 2026-05-16T05:51:45.969Z
title: Shift network model to client-trust + server illegal-position fall trigger
area: general
status: promoted
promoted_to: .planning/phases/06.7-network-model-client-trust-fall-trigger/06.7-SEED.md
promoted_at: 2026-05-17
files:
  - apps/server/src/RebnoRoom.ts
  - apps/client/src/prediction/reconciler.ts
  - packages/game-logic/src/collision.ts
  - apps/server/src/state.ts
  - apps/client/src/net/colyseus-client.ts
  - CLAUDE.md (Hard Rule 1)
---

## Problem

Current model is hybrid client-prediction + server-authoritative with reconciler snap-back when divergence exceeds threshold. Operator UAT on staging surfaced **movement feels choppy** because server is force-correcting predicted positions back to positions the player "shouldn't" be at (small reconciler snaps mid-walk). This game's feel depends on **predictable movement** — every input → exact same on-screen response, no rubber-band.

Concrete symptom example from operator UAT (2026-05-16):
- Diagonal stop produces ~10px horizontal shift before movement ends — likely reconciler snap from client-vs-server position drift.

Current hard rule in CLAUDE.md says "Server-authoritative. Clients send intent. Server emits state. Never trust client positions." This rule needs revision for movement specifically.

## Solution

Two-phase plan:

**Phase A (now / pre-launch hardening):** Flip the trust model for player movement.
- Client owns its position. Sends `position_update {x, y, vx, vy, facing}` to server every tick.
- Server stores client-reported position as authoritative state.
- Server still owns: chat origin (verify), inventory, scores, combat math, room transitions, fall detection (Phase B).
- Reconciler in `apps/client/src/prediction/reconciler.ts` becomes a no-op for self-player (only used for REMOTE players where server state IS authoritative).
- Update CLAUDE.md Hard Rule 1: clarify movement is client-trusted; non-movement state stays server-authoritative.

**Phase B (when "fall" feature lands):** Server detects illegal positions, triggers fall as reset.
- Server keeps a tick-by-tick check: `isPositionLegal(player.x, player.y, room.walkable_grid)`.
- If position is illegal (e.g. unsupported over a void, inside a wall) for > N ticks (~250-500ms grace), server triggers fall event.
- Fall = forced animation + position reset to last-known-legal-position or designated "respawn" point.
- This is the anti-cheat backstop: client can lie about position but only briefly before fall resets them.

**Why this works for BNO specifically:**
- Original BNO is a peer-to-peer 39dll networking game where clients DID trust each other's positions — REBNO can mirror that feel.
- 50 CCU target means abuse window is narrow; fall mechanic handles boundary-cheat case.
- Predictable movement is the core value (per CLAUDE.md Core Value: "walk around and chat ... bug-free").

**Risks to weigh during planning:**
- Cheaters can teleport visually (mitigated by fall-reset, but visible to other players briefly).
- Two players claiming same position → server arbitration model needed for collisions between players.
- Position-update spam → rate-limit to game tick rate (30Hz per CLAUDE.md Extracted Constants).
- Backwards compat: existing reconciler code + tests need careful refactor or gate behind a feature flag during transition.

Defer to its own phase (likely 07+). Do NOT bundle into 06.4 — that phase is closing on gap-closure not architecture shift.
