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

144 lines
8.3 KiB
Markdown

---
title: "Sprint 27 — Server Briefing"
description: "ZoneTypeTemplate structs, Clippy cleanup, cargo audit CI, content/ move to server/, v0.1 YAML audit"
type: sprint
status: active
sprint: 27
team: "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):
```bash
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): description" --description "body" --base main --head server
```