Files
settled-reach/docs/sprints/sprint-21/server.md
T
jpmschweitzerandClaude Opus 4.6 bc226d8baf chore(db): move db/connectors/ to tooling/db/ (#274)
Consolidates all connector scripts under tooling/ per project
structure conventions. Symlink at db/connectors → tooling/db/
preserves backwards compatibility (remove after Sprint 22).

Updated references in CLAUDE.md, Makefile, DEVOPS.md, all skill
files, agent files, rules, schema comments, and Sprint 21
briefings. Python scripts updated with correct SCHEMA_PATH
(now relative to WORKTREE_ROOT/db/schema.sql).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:08:00 +01:00

7.8 KiB

Sprint 21: Instantiate — Server Tasks

Goal: The template system becomes executable — templates spawn NPCs, assign triangles, and place them in world space; cross-template triangles link social sites; the client gains save/load game flow; and the generator pipeline gets its architectural design.

Branch: server Agents: Dudley (simulation dev), Tyre (arch), Hoshe (QA)

New Tickets

# Title Blocked by
#159 Tier 2 template definition format — (#158 done)
#166 Template-to-instance mapping — (#163, #164, #165 done)
#161 Template instantiation engine #166
#108 Cross-template triangle generation — (#106, #107 done)
#109 Triangle validation — (#107 done)
#85 Error handling & recovery
#246 Basic environmental interaction

Use tooling/db/ticket show <id> for full details on any ticket.

Key Decisions

  • decisions/content.md — D-023 (three-tier content model), D-024 (NPC generation model, 10 axes), D-025 (social site as atomic template unit), D-028 (dialogue tagged pools), D-029 (population entanglement ratio)
  • decisions/architecture.md — D-020 (Godot + Rust IPC, ObserverSnapshot), D-010 (deterministic simulation), D-087 (v0.1 triangle configuration), D-088 (3-state pause, server-authoritative), D-089 (self-contained forks, no cascade)

Notes

#159 — Tier 2 template definition format

  • server/src/content/template.rs already defines RoleSchema, SpaceSpec, TriangleDef (Sprint 20). #158 (Tier 1 drama module schema) is done — use it as a reference for YAML conventions.
  • This ticket extends that to the full Tier 2 document: roles, spaces, triangles, dialogue pool references, NPC routines, and spatial spec in one YAML document.
  • server/data/templates/ directory exists (created by #385). Place the canonical Tier 2 schema definition and at least one authored example template here.
  • Acceptance: a complete Tier 2 template YAML round-trips cleanly through RoleSchema / SpaceSpec deserialization.

#166 — Template-to-instance mapping

  • Depends on the schema from #159, but #159 is partially stubbed already — Dudley can start here in parallel if schema is stabilising.
  • Core task: given a loaded TemplateOwnership + SpaceSpec, spawn NPC entities for each role slot, assign relationships, and record the mapping in TemplateReferenceMap.
  • Existing hook: server/src/content/spawn.rs. The TemplateOwnership component (Sprint 20) already tracks which template owns an entity. This ticket wires spawning to that system.
  • Instance lifecycle: entities spawned from a template must be tagged such that they can be despawned/reset cleanly (gauntlet room reset pattern in server/src/test_world/ is a reference).
  • Acceptance: unit test spawns a 4-NPC template, asserts all role slots filled, TemplateOwnership set correctly on each entity, TemplateReferenceMap entries present.

#161 — Template instantiation engine

  • Blocked by #166. Once mapping works, this ticket wires the full pipeline: load YAML → deserialize → call spawn → generate triangles via server/src/content/template.rs:assign_triangle_roles() → register ownership.
  • Instance lifecycle management: track active instances, support unloading (for zone transitions and save/load).
  • Integration point with #166: the instantiation engine calls the mapping layer, not the raw spawn functions.
  • Acceptance: end-to-end test — load server/data/templates/ logistics_hub YAML, instantiate it, assert NPCs exist with correct roles and 2+ TriangleState components generated.

#108 — Cross-template triangle generation

  • Sprint 20 landed intra-template triangles (#107). This ticket adds the 1 cross-template triangle required by D-024 ("2 per template minimum, 1 cross-template").
  • The existing assign_triangle_roles() in server/src/content/template.rs takes &[TriangleDef] — extend to accept role slots from two different TemplateOwnership sources.
  • D-025 ownership model: NPCs are owned by one template but can hold reference roles in another. The cross-template triangle uses TemplateReferenceMap reference links (carrying relationship metadata) not direct ownership links.
  • Acceptance: test world with two instantiated templates (logistics hub + bar) produces 1 cross-template TriangleState with role assignments spanning both templates.

#109 — Triangle validation

  • Quality checks on generated triangles. Three checks minimum: (1) conflict viability — the three role slots have at least one opposing Want axis, (2) relationship coherence — at least one Relationships entry links the three roles, (3) interest divergence — no two roles share identical Want+Secret combination.
  • Validation runs at instantiation time (not a separate pass). Return Result<Vec<TriangleState>, ValidationError> from assign_triangle_roles().
  • Hoshe: unit tests for each failure mode — triangle that fails conflict viability, triangle that fails coherence, triangle that fails divergence.
  • Acceptance: cargo test -p server -- triangle_validation passes, covering all three failure modes plus a valid triangle that passes all checks.

#85 — Error handling & recovery

  • Handle three categories: (1) simulation panics / process crashes, (2) protocol deserialization errors, (3) desync detection between client state and server state.
  • Server side: server/src/bridge/local.rs is the IPC entry point. Add a supervision layer that catches panics from the tick loop and sends a structured SimError message to the client before dying, rather than an abrupt disconnect.
  • Protocol errors: server/src/bridge/types.rs — ensure malformed input returns a typed error response, not a panic. The existing malformed_input_in_batch_rejects_entire_batch test (#479, done) is the baseline.
  • Desync: add a state_hash field to ObserverSnapshot (a fast hash of key mutable state — player position, NPC count, tick number). Client logs hash mismatches for debugging. No automatic recovery in v0.1 — detect and report only.
  • Acceptance: integration test sends a deliberately malformed message mid-session, asserts the server emits a SimError message and continues running (does not exit).

#246 — Basic environmental interaction

  • ObjectType enum is already in server/src/bridge/types.rs (extended by #421, #422). Interactable component is in server/src/simulation/interaction.rs.
  • Currently ObjectType::Door, ObjectType::Terminal, ObjectType::Readable, ObjectType::Container, ObjectType::Furniture exist with verb sets.
  • This ticket: implement the behaviour behind Door (toggle walkable on the blocking tile(s), emit a zone-crossable notification), Examinable objects (return examine text from content), and usable Terminals (trigger a TerminalInteracted event for future dialogue hook).
  • Door state must be tracked in SaveStateV1 (currently a field gap — add open_doors: Vec<StableId> to the save struct in server/src/simulation/save_state.rs).
  • Acceptance: unit test — player interacts with a Door entity, asserts walkability flips; interacts again, asserts it flips back. Examine on a Readable entity returns non-empty text.

Dependency Chain

#159 (Tier 2 template format) → #166 (template-to-instance mapping) → #161 (instantiation engine)
#107 (done: intra-template triangles) → #108 (cross-template triangles) → #109 (triangle validation)
#85 (error handling) — standalone
#246 (environmental interaction) — standalone

Parallel tracks: #159→#166→#161 and #108→#109 can run concurrently. #85 and #246 are independent.

PR Workflow

When ready to submit, create a PR with tea CLI:

tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): Sprint 21 template instantiation" --description "body" --base main --head server