diff --git a/docs/backups/settledreach.db.backup b/docs/backups/settledreach.db.backup index b5e4b4708..47c104f19 100644 Binary files a/docs/backups/settledreach.db.backup and b/docs/backups/settledreach.db.backup differ diff --git a/docs/sprints/sprint-30/client.md b/docs/sprints/sprint-30/client.md new file mode 100644 index 000000000..06a7113c1 --- /dev/null +++ b/docs/sprints/sprint-30/client.md @@ -0,0 +1,103 @@ +# Sprint 30: Clean Slate — Client Tasks + +**Goal:** Close Phase 1 wiki quality debt — stereotype correction, data integrity fixes, and atlas regressions — so the wiki stands correct before Phase 1 UI work begins. + +**Branch:** `client` +**Agents:** Stig (dev), Tyre (arch), Hoshe (QA) + +## New Tickets + +| # | Title | Priority | Blocked by | +|---|-------|----------|------------| +| #718 | Persist CharacterVisualDescriptor on new game start | high | — | +| #674 | Star map insert module — concentric hop-ring view | medium | — | +| #712 | Add BoneAttachment3D marker above Head bone for floating icons | medium | — | +| #719 | Hair highlight: add descriptor field or make swatch read-only | medium | — | +| #720 | Replace DirAccess asset scanning with manifest JSON for export builds | medium | — | + +Use `tooling/db/ticket show ` for full details. + +## Key Decisions + +- `decisions/architecture.md` — D-134 (full character customisation: hair, clothing, colors at tile scale), D-146 (character preview: tile-scale sprite, no separate portrait), D-043 (art direction: functional warmth), D-044 (visual hierarchy) +- `decisions/scope.md` — D-114 (Phase 4 deliverable: player viewport with final-version assets) + +## Notes + +### Existing code to understand first + +Before starting any ticket, read: + +- `client/ui/character_creation.gd` — the character creation screen. Manages `CharacterVisualDescriptor`, layer selectors, color swatches, preview pane, and manifest loading. +- `client/assets/characters/manifest.json` — asset manifest listing available body types, heads, hair, facial hair, clothing, accessories. Partially populated (heads array is empty). +- `client/scripts/autoloads/game_state.gd` — player entity ID and session state. CharacterVisualDescriptor will be stored here on new game start. +- `client/scripts/rendering/entity_renderer.gd` — current entity sprite system. Integration point for #718 (persisted descriptor must survive into gameplay rendering). + +### #718 — Persist CharacterVisualDescriptor on new game start + +When the player confirms the character creation screen, the client sends a `CharacterVisualDescriptor` to the server. The server must receive it and persist it so the descriptor survives save/load cycles and is included in `ObserverSnapshot`. This ticket is the client side: wire the confirmed descriptor from `character_creation.gd` through to the new-game IPC call. Verify the descriptor reaches the server (coordinate with server team if the server-side storage is not yet implemented — server ticket is out of scope this sprint unless added separately). + +**What to deliver:** +- On confirm in `character_creation.gd`, serialize descriptor and include it in the new-game start message to the server +- Store descriptor in `GameState` so it persists across scene transitions +- After load, confirm descriptor is restored from server snapshot (integration test: start game, check descriptor fields match what was entered) + +**File locations:** +- `client/ui/character_creation.gd` — add serialization + send call +- `client/scripts/autoloads/game_state.gd` — add descriptor field + restore from snapshot +- `client/protocol/` — may need a new message type for descriptor transmission + +### #712 — BoneAttachment3D marker above Head bone + +Add an empty `Marker3D` node anchored as a `BoneAttachment3D` to the Head bone in the player character skeleton scene. Offset approximately 0.3m above the Head bone origin. This node is the anchor point for floating UI elements — status indicators, thought bubbles, alert markers, speech icons. + +**What to deliver:** +- Locate the skeleton scene (likely `client/assets/characters/skeleton/` or similar based on the Sprint 28 asset pipeline) +- Add `BoneAttachment3D` with bone_name = "Head", child `Marker3D` at offset Vector3(0, 0.3, 0) +- Export a `@export` var or named node path from the character root so other systems can reference the marker node without hardcoded paths +- No functional systems need to use this marker yet — the ticket is infrastructure for future floating UI work + +**Gotcha:** BoneAttachment3D must be a child of the skeleton, not the character root. If the skeleton is a `Skeleton3D` inside a scene, the attachment must be added inside that scene, not the parent. + +### #719 — Hair highlight: add descriptor field or make swatch read-only + +The hair highlight swatch in the character creation screen accepts user input but the override is a no-op. `CharacterVisualDescriptor` has no `hair_highlight_tint` field, and `_on_hair_highlight_changed` in `character_creation.gd` does not write to the descriptor. Two valid resolutions: + +**Option A (preferred if adding the field is low-risk):** Add `hair_highlight_tint: Color` to `CharacterVisualDescriptor` and wire `_on_hair_highlight_changed` to write it. The compositor must then read and apply it. This is the fuller fix. + +**Option B (if the compositor cannot accept it yet):** Make the swatch non-interactive — visually show the derived highlight color (`_derive_hair_highlight(descriptor.hair_tint)`) but remove the `ColorPickerButton` and replace with a plain `ColorRect` labeled "Auto". Add a `# TODO: ticket #719` comment noting the deferred field. + +Decide which option to implement based on compositor readiness. If the compositor already supports `hair_highlight_tint` (check `client/scripts/rendering/character_compositor.gd` if it exists), go with Option A. Otherwise Option B. + +### #720 — Replace DirAccess with manifest JSON + +The character creation screen uses `DirAccess.open("res://...")` in two fallback functions (around lines 1849 and 1868 in `character_creation.gd`) to scan for available assets. This approach fails in exported PCK builds because `DirAccess` cannot enumerate `res://` paths inside a PCK archive. + +The manifest approach is already partially implemented — `_load_manifest()`, `_manifest_array()`, and `MANIFEST_PATH` are in place. The manifest file at `client/assets/characters/manifest.json` exists and is partially populated. + +**What to deliver:** +- Remove the two `DirAccess.open()` fallback scanning functions (lines ~1849-1868) +- Populate `manifest.json` fully: add all available asset IDs for heads, hair, clothing, accessories, and body_types by scanning the actual asset directories once (during development) and encoding the result into JSON +- Add a `tooling/` script or `Makefile` target that regenerates `manifest.json` from the asset directories, so it stays in sync as artists add assets — this prevents the manifest going stale +- Verify: in an exported build (or by disabling DirAccess manually), the character creation screen populates all tabs correctly from the manifest alone + +**Note:** `manifest.json` currently has `"heads": []` — the heads array is empty. If head assets exist in `client/assets/characters/heads/`, add them. If none exist yet, leave empty but document in a comment that the manifest is the source of truth. + +## Dependency Chain + +``` +#718 (persist descriptor) — standalone, no client-side blockers +#719 (hair highlight) — standalone, read compositor state first +#720 (manifest JSON) — standalone +#712 (bone marker) — standalone +#674 (star map) — standalone +``` + +All five tickets are parallel tracks. No cross-dependencies within this sprint. + +## 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(client): Sprint 30 character and UI fixes" --description "body" --base main --head client +``` diff --git a/docs/sprints/sprint-30/copy.md b/docs/sprints/sprint-30/copy.md new file mode 100644 index 000000000..df928a184 --- /dev/null +++ b/docs/sprints/sprint-30/copy.md @@ -0,0 +1,106 @@ +# Sprint 30: Clean Slate — Copy Team Tasks + +**Goal:** Close Phase 1 wiki quality debt — stereotype correction, data integrity fixes, and atlas regressions — so the wiki stands correct before Phase 1 UI work begins. + +**Branch:** `copy` +**Agents:** Mellanie (author), Paula (narrative review), Miri (worldbuilding/naming) + +## New Tickets + +| # | Title | Priority | Blocked by | +|---|-------|----------|------------| +| #763 | fix(wiki): GJ1111 and GJ54.1 prose not updated for population rebalance | high | — | +| #772 | content(wiki): Afrikaans cultural stereotype imbalance at ~15:1 ratio | medium | — | +| #753 | Fix Mabuhay wiki: GJ 482A continuity error | medium | — | +| #757 | Fix Pereira's Rest wiki: population 800 → 42K | medium | — | +| #758 | fix(wiki): Langemark (GJ42) celestial bodies table uses non-schema values | medium | — | +| #759 | fix(wiki): Solheim (GJ19) topology disconnect | medium | — | +| #764 | fix(atlas): GJ1111 star_type reverted to unusual — regression from PR #101 | medium | — | +| #767 | fix(atlas): GJ707 star_type/spectral_class fields swapped | medium | — | +| #769 | fix(wiki): GJ-147 etymology says 'passagem' but system is named Entremeio | medium | — | +| #770 | fix(wiki): GJ-875 header says G-type but System Profile shows K5 | medium | — | +| #771 | fix(wiki): GJ-7547 and GJ-6711 spectral class truncated to bare 'K' | low | — | +| #754 | fix(wiki): update stale Calibration Notes on GJ1128, GJ136, GJ625 | low | — | +| #755 | fix(wiki): GJ432A wiki prose still says Punjabi-Canadian | low | — | +| #756 | fix(wiki): GJ541 header says G-type, proposal says K (K2IIIp) | low | — | +| #760 | fix(atlas): GJ601A needs F2III stellar evolution context in notes | low | — | +| #761 | fix(atlas): GJ4056 spectral_class 'g' is malformed | low | — | +| #765 | fix(wiki): South Reach rebalanced systems need calibration notes for small populations | low | — | +| #768 | fix(atlas): GJ189 wave_2 at hop 8-11 needs reconciliation | low | — | + +Use `tooling/db/ticket show ` for full details. + +## Key Decisions + +- `decisions/content.md` — D-121 (all content must be internally consistent), D-128 (culture implicit in starting location) +- `decisions/scope.md` — D-114 (wiki content phase is Phase 1 deliverable) + +## Notes + +### #763 — GJ1111 and GJ54.1 prose rebalance + +Both systems had populations reduced from 500M/800M tiers to 380K/320K. The wiki prose still describes the institutional depth, guild curricula, and transit apparatus of large hubs. Rewrite prose to match the actual populations — these are mid-tier settlements, not megahub capitals. Check both `wiki/star-systems/GJ-1111/index.md` and `wiki/star-systems/GJ-54.1/index.md`. + +### #772 — Afrikaans stereotype imbalance + +Cultural audit flagged ~15:1 confirming:subverting ratio for Afrikaans-coded systems. Recent additions (Eerste Wacht, Helderoog, Skemeraand) pushed pastoral/frontier stereotype further. The next Afrikaans-adjacent system authored this sprint must subvert the dominant register — urban, technocratic, industrial, or post-pastoral framing. This is a content authoring constraint, not a correction to existing pages. Coordinate with Miri on which candidate system to author and what subverting angle fits its astrophysics. Read `docs/audits/cultural-stereotyping-audit.md` before starting. + +### #753 — Mabuhay continuity error + +`wiki/star-systems/GJ-1073/index.md` references GJ 482A as an unsurveyed system in the silence topic and narrative hook. GJ 482A is Dagat — a 300-year-old wave_3 settlement with 210K people. Either reframe the mystery to a genuinely unsurveyed system, or rewrite the hook to reference Dagat correctly. Do not invent a new system — use an existing unsurveyed entry from the atlas. + +### #757 — Pereira's Rest population + +`wiki/star-systems/GJ-208/index.md` Faction Notes says "approximately eight hundred." The body catalog sets population to 42,000. One-line change in the prose; also verify no other sections use the 800 figure. + +### #758 — Langemark schema values + +`wiki/star-systems/GJ-42/index.md` celestial bodies table uses: `breathable` (should be `standard`), `rivers-lakes` (not a valid biome value), `west_reach` (not a valid economy/corridor tag). Normalize all three to schema-valid values. See `db/schema.sql` for valid enum values and `tooling/db/sqlite-query "SELECT DISTINCT atmosphere FROM bodies"` to confirm live values. + +### #759 — Solheim topology + +`wiki/star-systems/GJ-19/index.md` references Caldwell Point for food routing and describes food exports to loop neighbors, but the adjacent-system topology links are absent or broken. Either add the topology references to the proposal JSON (if the links are real and just not encoded), or rewrite the narrative to remove the claims. Do not fabricate topology — check `tooling/db/sqlite-query "SELECT * FROM gates WHERE system_id IN (SELECT id FROM star_systems WHERE gj_id='GJ19')"` to confirm real connections. + +### #764 — GJ1111 star_type regression + +PR #101 specifically corrected GJ1111 from `unusual` to `M`. A later PR reverted it. M6.5 is an extreme red dwarf but classifiable as M. Fix `star_type` back to `M` in the proposal JSON. If `unusual` has been redefined to cover edge cases like M6.5, document the reasoning in a Calibration Note rather than using `unusual` as a classification workaround. + +### #767 — GJ707 field swap + +`GJ707` (Dois Sóis) has `star_type: unusual` and `spectral_class: binary` — these are inverted. Should be `star_type: binary` with actual spectral classification in `spectral_class`. Also check `body_ids` — a binary system likely uses two-star naming conventions (A/B suffix) that may need correcting. + +### #769 — GJ-147 etymology + +`wiki/star-systems/GJ-147/index.md` line 21 explains "The name passagem is Portuguese" but the system is named Entremeio (meaning "in-between"). Fix wiki text to match the actual name. Then update the proposal JSON to ensure the `name_etymology` field (if present) reflects Entremeio, not passagem. + +### #770 — GJ-875 header/profile mismatch + +Wiki header says G-type; System Profile table shows K5. A Calibration Note acknowledges the discrepancy but the header was never corrected. Fix the header to K-type. Remove or simplify the Calibration Note — once the header is correct the note is redundant. + +### Low-priority fixes (#754, #755, #756, #760, #761, #765, #768, #771) + +All are small targeted corrections from PR reviews. Handle these after the high/medium tickets. Batch-address where possible but keep each change in its own commit with the ticket number in the message. + +- **#754** — Calibration Notes on GJ1128, GJ136, GJ625 describe pre-fix header mismatches that no longer exist. Remove or update the notes. +- **#755** — `wiki/star-systems/GJ-432A/index.md` line 25: change "Punjabi-Canadian research tradition" to "Punjabi heritage research tradition". +- **#756** — GJ541 (Chandra Deep) wiki header says G-type; proposal has K, K2IIIp. Update header to K-type. +- **#760** — GJ601A (Ostmark) proposal notes need acknowledgment of F2III bright giant finite habitability window, increased UV load, and polar settlement rationale. +- **#761** — GJ4056 has `spectral_class: g` (lowercase, no subtype). Correct to proper classification (G5V or similar based on star mass/luminosity). +- **#765** — GJ54.1, GJ1111, GJ905 populations diverge significantly from heuristics table. Add Calibration Notes to proposals marking these as intentional small populations (not authoring errors). +- **#768** — GJ189 (Altgrund) is `wave_2` but at hop 8-11. Either wave is wrong, hop is wrong, or there is an in-setting explanation (old route, pre-gate era colony). Reconcile: add a Calibration Note if the inconsistency is intentional and explainable, otherwise correct the field. +- **#771** — GJ-7547 and GJ-6711 System Profile tables show bare `K` instead of full spectral class (e.g. `K4V`). Update wiki tables to match proposal JSON. + +## Dependency Chain + +``` +All tickets are independent — no blocking dependencies within this sprint. +Process high-priority tickets first, then medium, then low. +#772 (Afrikaans subversion) requires Miri involvement for system selection. +``` + +## 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 "fix(wiki): Sprint 30 wiki quality fixes and atlas regressions" --description "body" --base main --head copy +``` diff --git a/docs/sprints/sprint-30/joint.md b/docs/sprints/sprint-30/joint.md new file mode 100644 index 000000000..be89514a9 --- /dev/null +++ b/docs/sprints/sprint-30/joint.md @@ -0,0 +1,52 @@ +# Sprint 30: Clean Slate — Joint Briefing + +**Goal:** Close Phase 1 wiki quality debt — stereotype correction, data integrity fixes, and atlas regressions — so the wiki stands correct before Phase 1 UI work begins. + +**Sprint number:** 30 +**Theme:** Clean Slate +**Status:** planning + +## Pre-Sprint Checklist + +| Item | Owner | Status | +|------|-------|--------| +| Epics #638, #683, #738 closed (all children done) | SI | done | +| #772 assigned to copy team | SI | done | +| All 26 tickets assigned to Sprint 30 | SI | done | + +## Ticket Summary by Team + +| Team | Count | Priority breakdown | +|------|-------|--------------------| +| copy | 18 | 1 high, 9 medium, 8 low | +| client | 5 | 1 high, 4 medium | +| server | 3 | 3 medium | +| **total** | **26** | | + +## Sprint Completion Proof + +The sprint is done when: + +1. **Wiki accuracy:** GJ1111 and GJ54.1 prose matches actual populations (380K/320K, not 500M/800M tier language) +2. **Atlas correctness:** GJ1111 `star_type = M` (not `unusual`), GJ707 `star_type = binary` with proper spectral_class +3. **Schema compliance:** Langemark celestial bodies table uses only schema-valid values; `tooling/db/sqlite-query "SELECT DISTINCT atmosphere FROM bodies"` returns no `breathable` entries from new commits +4. **Stereotype balance:** One new Afrikaans-adjacent system authored this sprint that subverts the pastoral/frontier register +5. **Client stability:** Character creation screen populates from manifest.json without DirAccess fallback; hair highlight swatch either wired to descriptor or marked read-only +6. **Server reliability:** `settings.db` is auto-created on first run; `habitable_planet_count` is non-zero for systems with `atmosphere = standard` planets after fix + +## Cross-Team Dependencies + +**Client → Server (#718):** The client sends `CharacterVisualDescriptor` on new game start. If server-side persistence is needed (storing descriptor in save file, returning in `ObserverSnapshot`), that work is not in Sprint 30's server tickets. Stig should verify what the server currently does with the descriptor on receipt before assuming it is handled. If server-side work is needed, raise with SI to create a follow-up ticket. + +**Copy → Server (#762):** The `breathable` vs `standard` filter fix in atlas.rs affects all future copy team commits. Server team should ship this fix early so copy team's Sprint 30 wiki commits produce correct `habitable_planet_count` values. + +## Deferred to Sprint 31 + +- **#766** — Cultural diversity sweep (full sweep across all 5 corridors) — too large for this sprint, scoped as its own sprint +- **#675** — Gate network travel planner — deferred + +## Notes + +No planning tickets in this sprint — all decisions are already made. Sprint 30 is execution-only: fix what the PR reviews flagged, apply the authoring constraint from the cultural audit, and clean up the character system. + +The cultural audit file at `docs/audits/cultural-stereotyping-audit.md` and `docs/audits/pr101-review-sample.diff` are the reference sources for the copy team's correctness tickets. Copy team should read both before starting the medium/high priority fixes. diff --git a/docs/sprints/sprint-30/server.md b/docs/sprints/sprint-30/server.md new file mode 100644 index 000000000..abd8f8aa5 --- /dev/null +++ b/docs/sprints/sprint-30/server.md @@ -0,0 +1,90 @@ +# Sprint 30: Clean Slate — Server Tasks + +**Goal:** Close Phase 1 wiki quality debt — stereotype correction, data integrity fixes, and atlas regressions — so the wiki stands correct before Phase 1 UI work begins. + +**Branch:** `server` +**Agents:** Dudley (dev), Tyre (arch), Hoshe (QA) + +## New Tickets + +| # | Title | Priority | Blocked by | +|---|-------|----------|------------| +| #762 | fix(atlas): habitable_planet_count filter uses 'breathable' but proposals use 'standard' | medium | — | +| #752 | Add settings.db creation-on-missing routine + gitignore | medium | — | +| #744 | Add corridor-status command to atlas CLI | medium | — | + +Use `tooling/db/ticket show ` for full details. + +## Key Decisions + +- `decisions/architecture.md` — D-094 (chunk size 32, district 256×256), D-139 (composable behavior primitives) +- `decisions/scope.md` — D-114 (server simulation is Phase 1 infrastructure) + +## Notes + +### #762 — habitable_planet_count filter mismatch + +**File:** `server/src/bin/atlas.rs`, `cmd_commit_system` function, line ~1293. + +The filter reads: +```rust +b.atmosphere.as_deref() == Some("breathable") +``` + +But all Track B/C/D body catalog proposals use `atmosphere: "standard"`, not `"breathable"`. As a result, `habitable_planet_count` is written as 0 for every committed system regardless of actual habitability. Fix the filter value to `"standard"`. Verify by querying the committed systems table after the fix: `tooling/db/sqlite-query "SELECT gj_id, habitable_planet_count FROM star_systems WHERE habitable_planet_count > 0 LIMIT 10"` should return non-zero counts after recommitting a test system. + +If both `"breathable"` and `"standard"` are valid atmosphere values that should count as habitable, update the filter to accept both: `matches!(b.atmosphere.as_deref(), Some("breathable") | Some("standard"))`. + +**Do not retroactively fix existing committed systems** — the fix applies to new commits. If you want to backfill, do it in a separate migration with a clear comment. + +### #752 — settings.db creation-on-missing + +**File:** `server/src/main.rs` lines 158-169, `server/src/settings/` module. + +`main.rs` calls `SettingsStore::open(&settings_path)` but if `settings.db` does not exist the call logs a warning and continues without settings persistence — it does not crash, but it silently degrades. Improve this: + +1. In `SettingsStore::open()` (likely in `server/src/settings/store.rs`), if the file does not exist, create it with default schema. Use `rusqlite::Connection::open()` which creates the file if absent, then run the settings schema `CREATE TABLE IF NOT EXISTS` DDL on first open. +2. Add `settings.db` to `.gitignore` (it is a runtime artifact, not source). +3. Verify: delete `settings.db`, run the server binary, confirm `settings.db` is created and the server starts without warnings about missing settings. + +**Schema reference:** Check `server/src/settings/types.rs` and `server/src/settings/store.rs` to understand the existing schema and what tables need to be created on first run. + +### #744 — corridor-status command for atlas CLI + +**File:** `server/src/bin/atlas.rs`. + +The atlas binary already has a subcommand infrastructure (clap-based, see lines 32-40). Add a `corridor-status` subcommand that shows remaining unfinished systems grouped by `geographic_sector` and `hop_distance`. Currently this is done via ad-hoc raw SQL queries. + +**What to deliver:** +- New `CorridorStatus` subcommand struct in atlas.rs +- Implementation queries `star_systems` for systems where body catalog is incomplete (no committed bodies, or `status != 'complete'` if such a field exists) +- Groups output by `geographic_sector`, then by `hop_distance` within each sector +- Output format: plain text table, corridor → hop → count of remaining systems, one row per corridor/hop combination +- Add to the atlas binary's help text + +**Query basis:** The equivalent SQL is approximately: +```sql +SELECT geographic_sector, hop_distance, COUNT(*) as remaining +FROM star_systems +WHERE body_catalog_complete = 0 OR body_catalog_complete IS NULL +GROUP BY geographic_sector, hop_distance +ORDER BY geographic_sector, hop_distance; +``` +Verify the actual column name against `db/schema.sql`. + +## Dependency Chain + +``` +#762 (breathable filter fix) — standalone +#752 (settings.db create) — standalone +#744 (corridor-status cmd) — standalone +``` + +All three tickets are parallel tracks. No cross-dependencies. + +## 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 "fix(server): Sprint 30 atlas filter, settings.db init, corridor-status cmd" --description "body" --base main --head server +```