docs: client vs server authority (#3) policy

Add modules/client_server_authority.md: default server truth for
persistence/economy/combat; intents vs state table; E1.M1–E1.M4 and
E5.M1 ownership; economy/quest/zone/PvP blanket; deferred tick rate
and lag comp.

Link from contracts.md, register, decomposition README, tech_stack;
one-line Authority pointers in E1_M1, E1_M2, E5_M1. Fix contracts.md
baseline link formatting.

Made-with: Cursor
pull/6/head
VinPropane 2026-03-30 18:53:29 -04:00
parent 8ac9953c92
commit 837251d439
8 changed files with 111 additions and 16 deletions

View File

@ -112,3 +112,4 @@ Revisit this document if:
- [`neon_sprawl_vision.plan.md`](../neon_sprawl_vision.plan.md) — product locks and phase gates
- [`docs/decomposition/README.md`](../decomposition/README.md) — epic/module decomposition
- [`docs/decomposition/modules/contracts.md`](../decomposition/modules/contracts.md) — contract kinds (wire, content, telemetry), repo layout, versioning vs. register “Contract needed”
- [`docs/decomposition/modules/client_server_authority.md`](../decomposition/modules/client_server_authority.md) — intents vs authoritative state; movement, camera, combat, economy ownership

View File

@ -9,7 +9,7 @@ This workspace contains detailed planning artifacts derived from the finalized m
## Folder Layout
- `epics/` - One file per epic with implementation slices.
- `modules/` - [Contract definitions (what a “contract” is)](modules/contracts.md), [full module dependency register](modules/module_dependency_register.md) (all epic modules), [per-module docs](modules/module_dependency_register.md#per-module-documentation), and interface notes.
- `modules/` - [Contract definitions](modules/contracts.md), [client vs server authority](modules/client_server_authority.md), [full module dependency register](modules/module_dependency_register.md) (all epic modules), [per-module docs](modules/module_dependency_register.md#per-module-documentation), and interface notes.
- `milestones/` - Phase-gated implementation tracks and pass/fail checklists.
## Working Rules

View File

@ -11,6 +11,8 @@
## Purpose
**Authority:** [Client vs server](client_server_authority.md#e1m1-inputandmovementruntime) — server owns `PositionState`; client sends move intent and may predict; reconcile to server.
Provides the foundational client/runtime path for character locomotion and world interaction: click-to-move or path-follow baseline, interaction trigger range checks, and the authoritative reconciliation surface for where the player is in the world. Other epics attach gameplay (gathering, combat, quests) on top of stable position and movement contracts.
## Responsibilities

View File

@ -11,6 +11,8 @@
## Purpose
**Authority:** [Client vs server](client_server_authority.md#e1m2-isometriccameracontroller) — camera is client-local for prototype; server does not use camera pose for gameplay checks.
Delivers a locked isometric camera that keeps the player readable during motion: follow behavior, discrete zoom bands, occlusion handling, and explicit **no rotation** so combat telegraphs and UI remain consistent with the vision for fixed isometric presentation.
## Responsibilities

View File

@ -11,6 +11,8 @@
## Purpose
**Authority:** [Client vs server](client_server_authority.md#e5m1-combatrulesengine) — server validates intents and computes all outcomes; never trust client damage/healing/crit/death.
Core tab-target combat resolution: valid actions against a locked target, hit resolution, cooldown and resource timing, and threat state as needed for prototype encounters. Presents readable outcomes in fixed isometric view and feeds XP awards through [E2.M2](E2_M2_XpAwardAndLevelEngine.md).
## Responsibilities

View File

@ -0,0 +1,82 @@
# Client vs server authority (Neon Sprawl)
This doc answers **who owns truth** for gameplay-relevant state and what the client may assume or predict. It complements [contracts.md](contracts.md) (what shapes cross the wire) and [`docs/architecture/tech_stack.md`](../../architecture/tech_stack.md) (stack locks).
---
## Default rule
- **Server** is authoritative for anything that affects **persistence**, **other players**, **economy**, **progression**, **security / PvP policy**, or **anti-cheat**.
- **Client** owns **input**, **presentation**, **UI**, **camera framing**, and **optional local prediction** that must **reconcile** to the server without changing committed outcomes.
Matches tech stack: client sends **intents**; server emits **state** (deltas or snapshots). Authoritative logic stays in **ASP.NET Core**, not Godot multiplayer templates.
---
## Intents vs authoritative state
| Direction | Content | Rule |
|-----------|---------|------|
| Client → server | **Intents** (move path, ability use, craft request, interact, chat, …) | Server validates every intent against rules, content, and current sim state. |
| Server → client | **Authoritative state** (`PositionState`, inventory, combat resolution, quest flags, zone tier, PvP eligibility, …) | Client displays and may predict; server wins on conflict. |
Naming on the wire may use `*Command` or `*Intent` for client→server and `*State` / `*Resolution` / snapshots for server→client; the **role** (intent vs truth) matters more than the suffix.
---
## By module (prototype defaults)
### E1.M1: InputAndMovementRuntime
- **Authoritative:** `PositionState` (and any rule derived from it: interaction range, zone presence) is owned by the **server** simulation.
- **Client:** Sends movement **intent** (e.g. destination, path id, or tick-aligned input—exact wire shape in Protobuf later). May **predict** the local avatar for responsiveness.
- **Reconciliation:** One documented ruleset: on server snapshot or correction, the client **must** converge to server truth (snap or blend—implementation choice; server outcome is final). Log material desync via [E9.M1 — TelemetryEventSchema](E9_M1_TelemetryEventSchema.md) when schema exists.
- **Deferred (not fixed here):** Sim tick rate, snapshot cadence, delta vs full snapshot protocol, and prediction smoothing curves—pick when networking MVP is scoped.
### E1.M2: IsometricCameraController
- **Authoritative:** **None** for prototype gameplay. Camera follow, zoom band, and occlusion are **client-local**; the server does **not** need `CameraState` for combat, zones, or PvP unless a future feature (e.g. replay) explicitly requires it.
- **Server:** Must not use client-reported camera pose for **gameplay checks** (targeting, line of sight, etc.); those use **world geometry + server-known positions**, not “what the player saw.”
### E1.M3: InteractionAndTargetingLayer
- **Authoritative:** Valid **target** and **interactable** eligibility (range, faction, phase, alive/dead) are decided on the **server**. Client sends selection or use **intent**; server responds with accepted `TargetState` or denial.
- **Client:** Hover, highlights, and tentative selection are presentation; may be wrong until server confirms.
### E1.M4: AbilityInputScaffold
- **Client:** Emits ability **intent** (`AbilityCastRequest` / equivalent) with ability id, target id, optional aim data as designed.
- **Server:** [E5.M1 — CombatRulesEngine](E5_M1_CombatRulesEngine.md) (and related systems) validate cooldowns, resources, range, facing/LOS rules, and [E6.M1](E6_M1_PvPEligibilityAndFlagState.md) where relevant; emits **CombatResolution** (or denies with reason).
### E5.M1: CombatRulesEngine
- **Never trust** client-supplied **damage**, **healing**, **crit rolls**, or **death** outcomes as source of truth.
- **Trust** only what the client can **observe** as intent: which action, which target, timing within tolerance—then **recompute** everything server-side from `SkillDef`, stats, and combat state.
### Economy, crafting, inventory, quests, zones, PvP
- **E3.\*, E7.\*, E4.\*, E6.\*:** Commit state and validate requests **only** on the server; client UI is a **view** over server-driven data. Already assumed in epics; this doc makes the split explicit for implementers.
---
## Telemetry and debugging
- **Authority violations** (client assumed an outcome the server denied) should be **visible**: denied intents with reason codes, optional lightweight desync counters—not silent fixes in production without logging.
---
## What this doc does not fix yet
- Exact **network update rate** and **interest management** (who receives which entity updates).
- **Lag compensation** model for tab-target combat (if any)—decide with combat design and E5.M1 implementation.
- **Rollback** vs **hard snap** reconciliation for movement—engineering choice after first multiplayer vertical slice.
Revisit when the first **Protobuf** game channel and a **multiplayer** milestone are defined.
---
## Related docs
- [`docs/architecture/tech_stack.md`](../../architecture/tech_stack.md) — server-authoritative critical paths, intents vs state
- [contracts.md](contracts.md) — wire vs content artifacts
- [Module dependency register](module_dependency_register.md)

View File

@ -4,19 +4,21 @@ Decomposition modules and the [dependency register](module_dependency_register.m
This doc fixes **artifact types**, **ownership**, and **versioning** so “Contract needed” in the register is actionable.
**Baseline stack alignment:** [`docs/architecture/tech_stack.md`](../../architecture/tech_stack.md) — authoritative server in C#; client in Godot/GDScript; **Protobuf** for versioned clientserver messages (JSON acceptable only for the earliest spike); **JSON/YAML + JSON Schema** for content tables.
**Baseline stack alignment:** [tech stack](../../architecture/tech_stack.md) — authoritative server in C#; client in Godot/GDScript; **Protobuf** for versioned clientserver messages (JSON acceptable only for the earliest spike); **JSON/YAML + JSON Schema** for content tables. **Who owns truth** for movement, camera, and combat: [client vs server authority](client_server_authority.md).
---
## Contract kinds
| Kind | Use for | Authoritative form | Typical consumers |
|------|---------|-------------------|-------------------|
| **Wire** | Player intents, state snapshots, RPC payloads crossing the network | **Protocol Buffer** `.proto` definitions; generated C# on server; mirrored types or codegen path in GDScript client | Client runtime, server host |
| **Server-internal** | Shapes used only inside the ASP.NET process (persistence DTOs, internal queues) until promoted | **C#** records/types in the server solution; behavior covered by tests | Server modules only |
| **Content** | Data-driven defs (`SkillDef`, `RecipeDef`, `QuestDef`, …) | **JSON or YAML** files + **JSON Schema** (or **CUE** later) validated in CI | Server load; tools; optional client bundles |
| **Telemetry** | Analytics and ops events ([E9.M1](E9_M1_TelemetryEventSchema.md)) | Versioned **event catalog** (JSON Schema or equivalent) + transport envelope; align names with OpenTelemetry where practical | Client emitters, ingest, dashboards |
| **HTTP (optional)** | Health, admin, or tooling — not the primary game sim path | **OpenAPI** if exposed; keep game loop on Protobuf per tech stack | Ops, CI, external tools |
| Kind | Use for | Authoritative form | Typical consumers |
| ------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| **Wire** | Player intents, state snapshots, RPC payloads crossing the network | **Protocol Buffer** `.proto` definitions; generated C# on server; mirrored types or codegen path in GDScript client | Client runtime, server host |
| **Server-internal** | Shapes used only inside the ASP.NET process (persistence DTOs, internal queues) until promoted | **C#** records/types in the server solution; behavior covered by tests | Server modules only |
| **Content** | Data-driven defs (`SkillDef`, `RecipeDef`, `QuestDef`, …) | **JSON or YAML** files + **JSON Schema** (or **CUE** later) validated in CI | Server load; tools; optional client bundles |
| **Telemetry** | Analytics and ops events ([E9.M1](E9_M1_TelemetryEventSchema.md)) | Versioned **event catalog** (JSON Schema or equivalent) + transport envelope; align names with OpenTelemetry where practical | Client emitters, ingest, dashboards |
| **HTTP (optional)** | Health, admin, or tooling — not the primary game sim path | **OpenAPI** if exposed; keep game loop on Protobuf per tech stack | Ops, CI, external tools |
A single logical name (e.g. `MoveCommand`) might appear as a **protobuf message** on the wire and a **different** internal server type that maps to/from it; the **wire schema** is what client and server must agree on. Until Protobuf exists for a message, a spike may use JSON with an explicit **throwaway** note in PRs and a tracked issue to migrate.
@ -38,11 +40,13 @@ When unsure, default to **wire protobuf** for anything the **Godot client** must
Paths are **conventions** until the first codegen lands; adjust in one doc PR when you add the first artifact.
| Artifact | Planned location | Notes |
|----------|------------------|--------|
| `.proto` files | `contracts/proto/` (repo root) | Keeps schemas visible to both server and client tooling; generate C# into `server/` and client bindings per chosen Godot/protobuf workflow |
| JSON Schema for content | `contracts/schemas/content/` (or co-located `schema.json` next to data) | Validate in CI before server boot in strict modes |
| Telemetry catalog | `contracts/schemas/telemetry/` or under `docs/` until ingest exists | Must carry **schema / semver** for [E9.M1](E9_M1_TelemetryEventSchema.md) |
| Artifact | Planned location | Notes |
| ----------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `.proto` files | `contracts/proto/` (repo root) | Keeps schemas visible to both server and client tooling; generate C# into `server/` and client bindings per chosen Godot/protobuf workflow |
| JSON Schema for content | `contracts/schemas/content/` (or co-located `schema.json` next to data) | Validate in CI before server boot in strict modes |
| Telemetry catalog | `contracts/schemas/telemetry/` or under `docs/` until ingest exists | Must carry **schema / semver** for [E9.M1](E9_M1_TelemetryEventSchema.md) |
Server-only helpers stay next to features (e.g. `NeonSprawl.Server/Game/...`) until extracted to a shared assembly if multiple hosts need them.
@ -74,6 +78,8 @@ A modules register **Status** can move to **Ready** when the contracts it **e
## Related docs
- [`docs/architecture/tech_stack.md`](../../architecture/tech_stack.md) — Protobuf vs JSON spike, content validation, client/server split
- [tech stack](../../architecture/tech_stack.md) — Protobuf vs JSON spike, content validation, client/server split
- [Client vs server authority](client_server_authority.md) — intents vs state, E1/E5 defaults, deferred networking choices
- [Module dependency register](module_dependency_register.md)
- [Decomposition README](../README.md)

View File

@ -2,7 +2,7 @@
Tracks cross-epic dependencies and contract readiness. Every **Depends On** module ID in this table has its own row (closed graph).
**Contract** means a stable boundary with a defined artifact (Protobuf wire message, JSON Schema content file, telemetry catalog entry, or server-internal type until promoted). See **[What a contract is](contracts.md)** for kinds, repo layout, and versioning.
**Contract** means a stable boundary with a defined artifact (Protobuf wire message, JSON Schema content file, telemetry catalog entry, or server-internal type until promoted). See **[What a contract is](contracts.md)** for kinds, repo layout, and versioning. **Authority** (who owns `PositionState`, camera, combat outcomes): **[Client vs server authority](client_server_authority.md)**.
Fleshed-out scope, contracts, and integration notes live in **per-module documents** (see [Per-module documentation](#per-module-documentation)).