neon-sprawl/docs/decomposition/modules/contracts.md

87 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# What a “contract” is (Neon Sprawl)
Decomposition modules and the [dependency register](module_dependency_register.md) use **contract** as the name for a **stable boundary**: something two systems (client and server, two server subsystems, or server and content pipeline) can depend on without sharing an undocumented struct.
This doc fixes **artifact types**, **ownership**, and **versioning** so “Contract needed” in the register is actionable.
**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 |
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.
---
## Mapping module “Key contracts” to kinds
Rough default (exceptions per module):
- **Intents and state sync** (`MoveCommand`, `PositionState`, `CombatAction`, `CombatResolution`, …) → **Wire** (protobuf).
- **Catalog / defs** (`RecipeDef`, `QuestDef`, `ItemDef`, `SkillDef`, …) → **Content** (files + JSON Schema).
- **Pure server resolution** (e.g. internal threat tables, idempotency keys not sent to client) → **Server-internal** until a client or tool needs them; then promote to wire or document as admin-only HTTP.
When unsure, default to **wire protobuf** for anything the **Godot client** must send or interpret; default to **content + schema** for anything authored as **bulk data**.
---
## Repository layout (convention)
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) |
Server-only helpers stay next to features (e.g. `NeonSprawl.Server/Game/...`) until extracted to a shared assembly if multiple hosts need them.
---
## Naming
- Register and epics use **PascalCase** names (`CraftRequest`, `LevelUpEvent`). **Protobuf messages** use the same PascalCase style; **protobuf field names** follow `snake_case` in `.proto` if you adopt common style guides (generated C# still maps to idiomatic names).
- **JSON Schema** `$id` and file names should include a **version** or folder (`v1/`) when breaking changes ship.
---
## Versioning and “Ready”
- **Wire:** additive changes via new fields and reserved numbers; breaking changes require a **new message** or a negotiated major bump and client rollout strategy.
- **Content:** schema version in CI; server rejects or migrates unknown versions per policy.
- **Telemetry:** bump **EventSchemaVersion** (E9.M1); document in changelog for dashboards.
A modules register **Status** can move to **Ready** when the contracts it **exports** are published in the agreed form (proto checked in, or schema in CI, plus a minimal consumer test or stub).
---
## What this doc does not decide
- **Exact** Protobuf package layout and service vs unary choices — decide when the first real RPC is added.
- **Godot** protobuf library choice — tooling decision; still must consume the same `.proto` truth as the server.
---
## Related docs
- [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
- [PvP and the combat engine](pvp_combat_integration.md) — E5.M1 gating with E6.M1, deny reasons
- [Module dependency register](module_dependency_register.md)
- [Decomposition README](../README.md)