From 8ac9953c924db16683cc7e086c51b4b33734b605 Mon Sep 17 00:00:00 2001 From: VinPropane Date: Mon, 30 Mar 2026 18:51:35 -0400 Subject: [PATCH] docs: define contract kinds and artifacts (wire, content, telemetry) Add modules/contracts.md: Protobuf wire vs server-internal vs JSON Schema content vs telemetry catalog; mapping Key contracts to kinds; proposed contracts/ repo layout; versioning and Ready criteria. Link from dependency register, decomposition README, tech_stack Related docs; pointer from E9.M1 module doc. Made-with: Cursor --- docs/architecture/tech_stack.md | 1 + docs/decomposition/README.md | 2 +- .../modules/E9_M1_TelemetryEventSchema.md | 2 + docs/decomposition/modules/contracts.md | 79 +++++++++++++++++++ .../modules/module_dependency_register.md | 2 + 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 docs/decomposition/modules/contracts.md diff --git a/docs/architecture/tech_stack.md b/docs/architecture/tech_stack.md index bdc24c4..6e233d7 100644 --- a/docs/architecture/tech_stack.md +++ b/docs/architecture/tech_stack.md @@ -111,3 +111,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” diff --git a/docs/decomposition/README.md b/docs/decomposition/README.md index b615f61..1020225 100644 --- a/docs/decomposition/README.md +++ b/docs/decomposition/README.md @@ -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/` - Cross-epic contracts, [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 (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. - `milestones/` - Phase-gated implementation tracks and pass/fail checklists. ## Working Rules diff --git a/docs/decomposition/modules/E9_M1_TelemetryEventSchema.md b/docs/decomposition/modules/E9_M1_TelemetryEventSchema.md index 899f90d..5127c33 100644 --- a/docs/decomposition/modules/E9_M1_TelemetryEventSchema.md +++ b/docs/decomposition/modules/E9_M1_TelemetryEventSchema.md @@ -11,6 +11,8 @@ ## Purpose +Artifact policy for telemetry (envelope, field naming, versioning) aligns with [contracts.md — contract kinds](contracts.md#contract-kinds) and **Telemetry** row. + Canonical taxonomy and versioning for gameplay and operations events: session, progression, economy, combat, PvP, movement desync, and integrity-adjacent signals. Provides the shared **envelope** so every epic can instrument consistently and breaking changes are explicit. ## Responsibilities diff --git a/docs/decomposition/modules/contracts.md b/docs/decomposition/modules/contracts.md new file mode 100644 index 0000000..896556f --- /dev/null +++ b/docs/decomposition/modules/contracts.md @@ -0,0 +1,79 @@ +# 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:** [`docs/architecture/tech_stack.md`](../../architecture/tech_stack.md) — authoritative server in C#; client in Godot/GDScript; **Protobuf** for versioned client–server messages (JSON acceptable only for the earliest spike); **JSON/YAML + JSON Schema** for content tables. + +--- + +## 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 module’s 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 + +- [`docs/architecture/tech_stack.md`](../../architecture/tech_stack.md) — Protobuf vs JSON spike, content validation, client/server split +- [Module dependency register](module_dependency_register.md) +- [Decomposition README](../README.md) diff --git a/docs/decomposition/modules/module_dependency_register.md b/docs/decomposition/modules/module_dependency_register.md index 4f62b7f..d63157a 100644 --- a/docs/decomposition/modules/module_dependency_register.md +++ b/docs/decomposition/modules/module_dependency_register.md @@ -2,6 +2,8 @@ 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. + Fleshed-out scope, contracts, and integration notes live in **per-module documents** (see [Per-module documentation](#per-module-documentation)). ## Dependency Table