Files
settled-reach/docs/sprints/sprint-25/server.md
T
jpmschweitzerandClaude Sonnet 4.6 0f1eda8d12 chore(meta): restructure Sprint 25 per feasibility study
Dependency chain inverted: #611 (NpcBlueprint structs) now goes first
and defines the schema contract. Copy team (#609, #610) fills YAML to
match Tyre's structs rather than the other way around.

#613 (NPC generation pipeline) cancelled and absorbed into #612 — the
NPC pipeline is the print loop at the end of the generator binary, not
a separate ticket.

Ticket descriptions loosened: strip over-specified acceptance criteria,
replace with intent + scope boundaries. Phoneme generation explicitly
out of scope for #610 (name lists are sufficient). #612 gains a phased
approach note (Phase 1: hardcoded stubs, Phase 2: real YAML) so server
can build in parallel with copy.

Briefings updated to reflect inverted chain, two-ticket server sprint,
and exploratory framing: this sprint discovers the right spec, it does
not implement a known one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 20:44:01 +01:00

5.6 KiB

Sprint 25: Emerge — Server Tasks

Goal: Prove the generator can extrapolate from minimal input — a rural Krenn area AND an industrial Krenn zone from zone type and culture profile alone, no per-location spec. Two zone types, one culture, side-by-side comparison.

Branch: server Agents: Dudley (simulation dev), Tyre (architect)

New Tickets

# Title Blocked by
#611 NpcBlueprint struct design — (starts immediately)
#612 Template assembly generator #611, #609 (copy), #610 (copy)

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

Key Decisions

  • decisions/scope.md — D-114 (generator-first proof-of-life), D-119 (generator spike critical path)
  • decisions/content.md — D-122 (all NPCs generated), D-128 (culture implicit in location), D-129 (NPC personality: traits + behavior first), D-121 (voice culture-driven), D-123 (AI content templating via culture vectors)
  • decisions/architecture.md — D-012 (chunk-based map, borderless generation future)

What Exists

  • server/src/simulation/generator.rs (576 lines) — DistrictSkeleton data model and related enums. Struct definitions only — no production generation logic yet.
  • server/src/npc/generate.rs — RoleDefinition-driven 10-axis NPC generator using SimRng (ChaCha20, deterministic). This pipeline survives; NpcBlueprint wraps above it and feeds into it.
  • server/src/simulation/rng.rs — SimRng. Use this for all randomness in the generator binary.
  • server/src/npc/ — full NPC component set including mood.rs, relationships.rs, routine.rs, trait_modifiers.rs.

Notes

Phased approach

This sprint discovers the right spec — it does not implement a known one. Three phases:

  • Phase 0 (#611): Define the Rust structs (ZoneSpec, CultureProfile, NpcBlueprint) and write example YAML. Share with copy team immediately — this unblocks #609 and #610.
  • Phase 1 (#612, early): Build the generator binary with hardcoded test data. Do not wait for copy to finish their YAML. Hardcode two zone profiles (rural, industrial stub) and a Krenn culture stub in Rust. Get the generation pipeline and stdout output working end-to-end.
  • Phase 2 (#612, late): Swap hardcoded stubs for real YAML loading from disk. Wire in copy's actual #609 and #610 files. Run the two-zone proof.

This phasing means the copy team's blocking relationship is on the final integration, not the generator build. Server can move through Phase 0 and Phase 1 in parallel with copy writing #609/#610.

#611 — NpcBlueprint struct design

  • Starts immediately. No blockers.
  • Define three structs in server/src/npc/blueprint.rs (new file):
    • ZoneSpec — deserializes from zone-identity-spec.yaml
    • CultureProfile — deserializes from culture-krenn.yaml
    • NpcBlueprint — generator output for a single NPC
  • All three derive Serialize, Deserialize (serde + serde_yaml).
  • NpcBlueprint fields: name (String), role (occupation), traits (Vec of trait enum), observable_behaviors (Vec), cultural_markers (speech register, filler words from culture profile), relationships (Vec of (npc_id, relationship_type, valence)).
  • Use a spike-specific SpikeOutput struct for the binary's top-level output — do NOT couple to DistrictSkeleton for the proof. Keep the spike isolated.
  • Key deliverable: write content/global/zone-identity-spec.example.yaml and content/global/culture-krenn.example.yaml showing the schema copy must fill. Share these with Miri before copy starts writing real content.
  • Add a note in the file header pointing to the tickets (#609, #610) that fill these schemas with real content.

#612 — Template assembly generator (absorbs #613)

  • Blocked by #611. Build Phase 1 before #609/#610 arrive; integrate in Phase 2.
  • Binary: cargo run --bin generator-spike -- --zone <type> --seed <n> (new binary in server/src/bin/).
  • Phase 1: hardcoded ZoneSpec and CultureProfile stubs in Rust. Focus on the generation logic and output formatting.
  • Phase 2: load zone spec and culture YAML from disk at runtime. Zone taxonomy is the file — adding a new zone type requires zero Rust changes.
  • Determinism: SimRng seeded from the --seed flag. Same inputs = same output.
  • NPC generation: use the existing npc/generate.rs pipeline. NpcBlueprint maps to RoleDefinition via a conversion method. The blueprint's cultural markers bias trait selection.
  • Stdout output per invocation: zone type header, NPC list (name, role, traits, one observable behavior), relationship pairs ("A knows B as colleague (positive)").
  • Sprint proof runs twice: --zone rural --seed 42 and --zone industrial --seed 42. The comparison is the test.

Dependency Chain

#611 (structs + example YAML) ──> copy #609 (zone spec) ──┐
                               ──> copy #610 (culture)  ──┴──> #612 (generator, Phase 2)
#611 ──────────────────────────────────────────────────────────> #612 (generator, Phase 1 — no YAML needed)

#611 first. Phase 1 of #612 runs in parallel with copy writing #609/#610. Phase 2 of #612 waits for both.

PR Workflow

When ready to submit, create a PR with tea CLI. All flags are required to avoid TTY prompts (see CLAUDE.md "Gitea access" section):

tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): generator spike — NpcBlueprint, template assembly, NPC pipeline" --description "body" --base main --head server