Files
settled-reach/docs/sprints/sprint-27/server.md
T
jpmschweitzerandClaude Sonnet 4.6 2fddf8b6ca chore(meta): plan Sprint 27: Scale
9 tickets assigned. Teams: server (5), copy (3), planning (1).
Sprint goal: extend zone-type template library from 2 to 31 zone types,
wire server structs for D-142, eliminate Clippy debt.

New ticket #676 created: assign teams to v0.2 story backlog (#614-#626).
Tickets #669 and #672 reassigned from maintenance to server.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:47:55 +01:00

8.3 KiB

title, description, type, status, sprint, team
title description type status sprint team
Sprint 27 — Server Briefing ZoneTypeTemplate structs, Clippy cleanup, cargo audit CI, content/ move to server/, v0.1 YAML audit sprint active 27 server

Sprint 27: Scale — Server Tasks

Goal: Extend the zone-type template library from 2 to 31 zone types, wire the server to load them, and eliminate Clippy debt — clearing the path to the NPC legibility sprint.

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

New Tickets

# Title Blocked by
#663 ZoneTypeTemplate and LocationSpec structs for D-142
#635 Clippy cleanup and CI enforcement
#637 Add cargo audit to CI/review pipeline
#669 Move content/ directory under server/
#672 Audit and flag v0.1 YAML content

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

Key Decisions

  • decisions/content.md — D-142 (zone-type template architecture — the schema this sprint implements), D-139 (composable behavior primitives — assemble_behaviors already in server/src/npc/blueprint.rs)
  • decisions/scope.md — D-114 (generator-first proof-of-life), D-122 (all NPCs generated)

Notes

#663 — ZoneTypeTemplate and LocationSpec structs

The existing ZoneSpec struct (server/src/npc/blueprint.rs, line 38) was authored for the Sprint 25 spike. The zone-type RON files the copy team has now shipped (content/global/zone-types/rural_agricultural.ron, industrial_freight.ron) use the D-142 format, which does not match the current struct. Four changes required:

1. Rename and extend ZoneSpec to ZoneTypeTemplate:

  • Add id: String — the canonical zone-type identifier (e.g. "rural_agricultural")
  • Add subtype: Option<String> — subtype discriminator (currently None in all files)
  • Rename social_sites: Vec<SocialSiteSpec> to social_site_types: Vec<SocialSiteTypeSpec>
  • The new SocialSiteTypeSpec uses eligible_roles: Vec<String> (role IDs), not min_npcs/max_npcs — those are location-spec metadata
  • economic_level and population_density become defaults, overridable by location specs

2. Update RoleSpec:

  • Remove weight: u8 — weights are declared on location specs, not zone-type templates. Roles in a zone-type template are authoritative behavior pools; location specs declare which roles appear and at what frequency.
  • behavior_primitives is the primary field; typical_behaviors is preserved as #[serde(default)] for backward compatibility until migration is verified.

3. Add LocationSpec struct:

  • zone_type: String — references a ZoneTypeTemplate.id
  • culture: String — references a culture profile
  • role_weights: Vec<RoleWeight>{ role_id: String, weight: u8 } entries
  • economic_level: Option<u8> — overrides zone-type default if set
  • population_density: Option<u8> — overrides zone-type default if set
  • abandoned: bool — D-142 abandoned flag
  • poi_overlay: Vec<String> — D-142 poi_overlay list
  • social_sites: Vec<LocationSocialSite> — site instances with site_type, label, min_npcs, max_npcs

4. Update loader in generator_spike.rs:

  • --from-files currently loads content/global/<zone>-zone-spec.ron. Update to load from content/global/zone-types/<zone_type>.ron.
  • Resolve (zone_type, role_id)BehaviorPrimitive pool by loading the ZoneTypeTemplate file then indexing by role ID.
  • The generator spike binary passes zone-type ID as --zone-type rural_agricultural (update the --zone arg). Keep --from-files mode.

Validate: After struct changes, run tooling/validate-ron content/global/zone-types/rural_agricultural.ron zone_type — it must pass without modification to the RON files. The RON files are the ground truth; the Rust structs must match them, not the other way around.

Test: Add a unit test in blueprint.rs that deserializes rural_agricultural.ron from disk and asserts the roles, primitive count, and social_site_types are non-empty. This test will fail until both the struct and the RON files align.

Schema registration in validate-ron: After struct changes, update server/src/bin/validate_ron.rs to accept zone_type as a schema name that deserializes to ZoneTypeTemplate.


#635 — Clippy cleanup and CI enforcement

Two-phase:

  1. One-time cleanup: Run cargo clippy --fix for auto-fixable warnings. Remaining complex warnings (too_many_arguments, complex type signatures) require manual refactors — fix by refactoring, not by suppressing with #[allow()]. Goal: zero warnings under --deny warnings.
  2. CI gate: Add cargo clippy -- --deny warnings to make pre-pr (see Makefile). After this sprint, Clippy warnings in PRs are a blocking failure.

Run cargo clippy -- --deny warnings 2>&1 | wc -l before starting to get a baseline count. The Gemini review found 66 warnings — verify the current count first (Clean House sprint may have reduced it). Fix in batches and commit frequently; a single large Clippy PR is hard to review.


#637 — Add cargo audit to CI/review pipeline

Trigger on Cargo.toml/Cargo.lock changes (not every commit). Approach:

  1. Add cargo audit target to Makefile under make audit.
  2. Wire it as a check in the CI configuration (.config/) that runs when Cargo.lock changes.
  3. Also add to make pre-pr so it runs locally before PRs.

The current open advisory is RUSTSEC-2025-0141 (bincode v1.3.3 unmaintained). cargo audit will flag it — this is expected until #636 (bincode migration, deferred) is completed. Add an advisory ignore for this specific ID so CI stays green while the known advisory is tracked, but new advisories will fail.


#669 — Move content/ directory under server/

content/ is consumed exclusively by the server (generator, validate-ron, tests). Move it to server/content/.

Steps:

  1. git mv content/ server/content/ — preserves git history.
  2. Update all path references in server Rust code: search for "content/" string literals in server/src/. Key files: server/src/bin/generator_spike.rs (default --content-root), server/src/bin/validate_ron.rs, any test fixtures.
  3. Update Makefile targets that reference content/.
  4. Update tooling/validate-ron script if it has hardcoded paths.
  5. Run make test after the move — fixture paths in integration tests may need updating.

Do not touch client/data/ — that is client-only and stays put.

After the move, tooling/db/sqlite-query 'SELECT * FROM tickets WHERE description LIKE "%content/global%"' to identify any ticket descriptions with stale paths (update them for future agents).


#672 — Audit and flag v0.1 YAML content

Survey task, not deletion. The server and copy branches contain ~67 YAML files from v0.1 that reference deleted named NPCs (Kael, Sera, Torek, etc.) and the detective arc.

Deliverable: A single file docs/architecture/v01-yaml-content-audit.md listing:

  • Each YAML file path and its status: deprecated (pure detective/named NPC content, no generator value), convertible (has useful data worth porting to RON generator format), or already-superseded (content was already replaced in main).
  • For convertible files: what specifically is worth extracting (name pools? voice patterns? dialogue seeds?).
  • Recommended disposition: archive vs delete vs convert.

Do not delete anything. Flag only. Deletion requires explicit team review in a follow-up ticket.


Dependency Chain

#669 (move content/) → must complete before #663 (loader path updates assume new location)
#663 (ZoneTypeTemplate structs) → unblocks copy team (#662) full pipeline run
#635 (Clippy cleanup) → #637 (cargo audit — add both to pre-pr in same pass)
#672 (v0.1 YAML audit) — standalone, parallel track

Note: #669 should ideally complete first so #663's loader uses the new server/content/ paths from the start. If they run in parallel, the loader path can target server/content/ directly and #669 will confirm the files are there.

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): description" --description "body" --base main --head server