chore(meta): switch Sprint 25 content format from YAML to RON
RON is Rust-native and struct-aware — the Rust structs ARE the schema. Includes RON validator CLI for the copy team to lint their files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,36 +24,38 @@ Use `tooling/db/ticket show <id>` for full details.
|
||||
|
||||
**How this sprint works for copy**
|
||||
|
||||
Server starts first. Tyre (#611) defines `ZoneSpec`, `CultureProfile`, and `NpcBlueprint` as Rust structs and writes example YAML showing the expected format. That YAML is the schema contract. Copy fills real content into that schema — not the other way around.
|
||||
Server starts first. Tyre (#611) defines `ZoneSpec`, `CultureProfile`, and `NpcBlueprint` as Rust structs and writes example RON files showing the expected format. The Rust structs ARE the schema — no separate schema file to maintain. Copy fills real content into that format.
|
||||
|
||||
Wait for #611 to deliver its example YAML before writing the real files. Coordinate with Tyre at sprint start to agree on file locations (`content/global/zone-identity-spec.yaml` and `content/global/culture-krenn.yaml` are the expected paths, but Tyre's struct design is authoritative).
|
||||
Wait for #611 to deliver its example RON before writing the real files. Tyre also ships a **RON validator CLI** (`tooling/validate-content <file.ron>`) that deserializes into the actual Rust structs and prints errors. Use it to lint your files before submitting.
|
||||
|
||||
Coordinate with Tyre at sprint start to agree on file locations (`content/global/zone-identity-spec.ron` and `content/global/culture-krenn.ron` are the expected paths, but Tyre's struct design is authoritative).
|
||||
|
||||
**#609 — Zone identity spec**
|
||||
|
||||
- Output: YAML file the generator deserializes at runtime. Schema defined by Tyre's `ZoneSpec` struct from #611.
|
||||
- Output: RON file the generator deserializes at runtime. Schema defined by Tyre's `ZoneSpec` struct from #611.
|
||||
- Minimum two zone types with real content: **rural** and **industrial**. These are the two the sprint proof runs. Remaining types can be stubs with plausible values.
|
||||
- The taxonomy must make the generator produce visibly different output per zone type — if rural and industrial look the same, it has failed.
|
||||
- Content scope: what varies between zone types (density, pace, social site mix, NPC role distribution). Not prose worldbuilding — structured parameters that the Rust generator can read.
|
||||
- Do not invent the schema. Read #611's example YAML first.
|
||||
- Do not invent the schema. Read #611's example RON first.
|
||||
|
||||
**#610 — Krenn culture profile**
|
||||
|
||||
- Output: YAML file the generator deserializes at runtime. Schema defined by Tyre's `CultureProfile` struct from #611.
|
||||
- Output: RON file the generator deserializes at runtime. Schema defined by Tyre's `CultureProfile` struct from #611.
|
||||
- Must provide enough cultural signal that generated NPCs feel Krenn, not generic-space-village.
|
||||
- Sprint scope: **name lists** (not phoneme generation rules — Tyre's generator picks from lists), speech markers, economic values, social norms.
|
||||
- Phoneme-based name generation is explicitly out of scope for this sprint. A curated list of Krenn-sounding names is sufficient.
|
||||
- Existing Krenn atmosphere and naming examples in `decisions/content.md` D-036 (amended post-workshop) are a starting point. Go deeper on concrete values (specific speech markers, actual name examples) not broader on atmospheric description.
|
||||
- Do not invent the schema. Read #611's example YAML first.
|
||||
- Do not invent the schema. Read #611's example RON first.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
server #611 (schema contract) ──> #609 (zone spec YAML) ──┐
|
||||
├──> server #612 (generator)
|
||||
──> #610 (culture YAML) ───────┘
|
||||
server #611 (schema + validator) ──> #609 (zone spec RON) ──┐
|
||||
├──> server #612 (generator)
|
||||
──> #610 (culture RON) ──────┘
|
||||
```
|
||||
|
||||
Server defines the shape. Copy fills it. Both #609 and #610 can be written in parallel once #611 delivers its example YAML.
|
||||
Server defines the shape. Copy fills it. Both #609 and #610 can be written in parallel once #611 delivers its example RON.
|
||||
|
||||
## PR Workflow
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ Use `tooling/db/ticket show <id>` for full details.
|
||||
|
||||
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.
|
||||
- **Phase 0 (#611):** Define the Rust structs (`ZoneSpec`, `CultureProfile`, `NpcBlueprint`) and write example RON files. Build the RON validator CLI. 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 RON files. 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 RON 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.
|
||||
|
||||
@@ -43,21 +43,22 @@ This phasing means the copy team's blocking relationship is on the final integra
|
||||
|
||||
- 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
|
||||
- `ZoneSpec` — deserializes from zone-identity-spec.ron
|
||||
- `CultureProfile` — deserializes from culture-krenn.ron
|
||||
- `NpcBlueprint` — generator output for a single NPC
|
||||
- All three derive `Serialize`, `Deserialize` (serde + serde_yaml).
|
||||
- All three derive `Serialize`, `Deserialize` (serde + `ron`). **Use RON format, not YAML/JSON.** RON is Rust-native, struct-aware, supports enums and comments. The Rust structs ARE the schema — no separate schema file to maintain.
|
||||
- `NpcBlueprint` fields: name (String), role (occupation), traits (Vec of trait enum), observable_behaviors (Vec<String>), 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.
|
||||
- Key deliverable: write `content/global/zone-identity-spec.example.ron` and `content/global/culture-krenn.example.ron` 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.
|
||||
- **Build a RON validator CLI** (`tooling/validate-content <file.ron>`) that deserializes into the actual Rust structs and prints errors. This is the copy team's lint tool — they run it to check their files without needing to compile the server. ~20 lines of Rust, ship it as part of #611.
|
||||
|
||||
**#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.
|
||||
- Phase 2: load zone spec and culture RON 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)").
|
||||
@@ -66,9 +67,9 @@ This phasing means the copy team's blocking relationship is on the final integra
|
||||
## 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 (structs + example RON + validator) ──> copy #609 (zone spec) ──┐
|
||||
──> copy #610 (culture) ──┴──> #612 (generator, Phase 2)
|
||||
#611 ──────────────────────────────────────────────────────────────────> #612 (generator, Phase 1 — no RON needed)
|
||||
```
|
||||
|
||||
#611 first. Phase 1 of #612 runs in parallel with copy writing #609/#610. Phase 2 of #612 waits for both.
|
||||
@@ -83,7 +84,7 @@ From Troblum's pre-sprint review. Read before starting.
|
||||
|
||||
3. **`DayPhase` name collision.** `server/src/simulation/generator.rs` defines `DayPhase = String` as a stub type alias, shadowing the real `DayPhase` enum in `server/src/simulation/time.rs`. Use the real enum explicitly or alias the stub out of scope before the spike binary sees both. Do not let the collision silently compile to the wrong type.
|
||||
|
||||
4. **Schema negotiation takes rounds.** The first YAML draft from copy will not deserialize cleanly. Build in slack between Phase 1 and Phase 2 — expect at least one round of struct adjustments after seeing real content.
|
||||
4. **Schema negotiation takes rounds.** The first RON draft from copy will not deserialize cleanly — the validator will catch this early. Build in slack between Phase 1 and Phase 2 — expect at least one round of struct adjustments after seeing real content.
|
||||
|
||||
## PR Workflow
|
||||
|
||||
|
||||
Reference in New Issue
Block a user