Compare commits

...
8 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.6 8d8da1b546 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 13:12:23 +01:00
jpmschweitzerandClaude Opus 4.6 d008874c14 chore(skills): add commit step to push-pr workflow
push-pr now runs /commit first when uncommitted changes are detected,
making it a one-stop commit→push→PR command. Added Skill to
allowed-tools for cross-skill invocation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 13:12:11 +01:00
jpmschweitzerandClaude Opus 4.6 370649b3df chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:53:00 +01:00
jpmschweitzerandClaude Opus 4.6 f13aafb1dd docs(meta): add asset pipeline and remote terminal proxy ideas to scratchpad
Two new scratchpad entries: asset generation pipeline improvements
(registry, status tracking, prompt versioning) and a remote terminal
proxy concept for mobile monitoring of Claude Code permission prompts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:52:49 +01:00
jpmschweitzerandClaude Opus 4.6 c2a3a251b4 feat(skills): start-sprint main workflow as state machine
On main, the skill now assesses sprint state and does the next right
thing: close active sprint (Case A), activate planned sprint (Case B),
or suggest /plan-sprint (Case C). Cases chain automatically — closing
flows into activation if a planned sprint is waiting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:15:56 +01:00
jpmschweitzerandClaude Opus 4.6 b4a3784218 docs(sprints): add Sprint 10 Prove briefings
Server (7), client (7), CI (3), audio (1) — 18 tickets total.
Gauntlet expansion, audio wiring, client UX polish, CI pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:12:45 +01:00
jpmschweitzerandClaude Opus 4.6 407018ecdf chore(meta): update changelog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:05:41 +01:00
jpmschweitzerandClaude Opus 4.6 973c804b52 feat(meta): add project.yaml as version source of truth
Technical project descriptor with game architecture, simulation
parameters, and content model. Version field (0.1.9) is now the
canonical version — Cargo.toml synced, CLAUDE.md and start-sprint
skill updated to reference it during release workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:05:29 +01:00
12 changed files with 683 additions and 33 deletions
+22 -10
View File
@@ -8,7 +8,7 @@ description: >
existing PR was updated. NEVER merges the PR into main — this skill only
pushes to the branch and manages the PR lifecycle.
user-invocable: true
allowed-tools: Bash, Read, Grep, Glob, AskUserQuestion
allowed-tools: Bash, Read, Grep, Glob, AskUserQuestion, Skill
---
# Push PR Skill
@@ -34,17 +34,29 @@ git branch --show-current
If on `main`, stop: "You're on main. Switch to a team branch first."
### 2. Check for unpushed commits
### 2. Commit uncommitted changes
```bash
git status
```
If there are uncommitted changes (staged or unstaged), run the **commit skill**
first. Use the `/commit` skill to group changes into logical commits with
proper conventional commit messages. Wait for commit to complete before
proceeding.
If the working tree is clean (no uncommitted changes), skip to step 3.
### 3. Check for unpushed commits
```bash
git fetch --all
git status
git log --oneline origin/<branch>..<branch>
```
If no unpushed commits, skip to step 4 (PR check).
If no unpushed commits, skip to step 5 (PR check).
### 3. Check for conflicts with main
### 4. Check for conflicts with main
```bash
git merge-tree --write-tree origin/main HEAD 2>&1
@@ -59,7 +71,7 @@ git merge origin/main --no-edit
If merge conflicts, **stop and report** — let the user resolve.
If clean, continue.
### 4. Push
### 5. Push
```bash
git push origin <branch>
@@ -67,7 +79,7 @@ git push origin <branch>
If push fails, stop and report. Never force-push without explicit request.
### 5. Check for existing PR
### 6. Check for existing PR
```bash
tea pr list --login schweitz --repo jpmschweitzer/settled-reach --state open --output simple
@@ -76,9 +88,9 @@ tea pr list --login schweitz --repo jpmschweitzer/settled-reach --state open --o
Match current branch name in PR list.
- **PR exists**: Report "Pushed N commits to `<branch>`. PR #X updated." Done.
- **No PR**: Continue to step 6.
- **No PR**: Continue to step 7.
### 6. Create a new PR
### 7. Create a new PR
```bash
git log --oneline main..<branch>
@@ -103,7 +115,7 @@ tea pr create \
Report PR URL when done.
### 7. Update ticket status to review
### 8. Update ticket status to review
Scan all commit messages in the PR for ticket references (`#NNN`):
+71 -21
View File
@@ -1,12 +1,12 @@
---
name: start-sprint
description: >
Start sprint work on a team branch, or close a sprint from main. Use when
the user says "start sprint", "start working on the server/client/copy",
"begin sprint", or invokes /start-sprint. On a team branch: merges main,
finds the active sprint, reads the briefing, presents the work plan. On
main: closes the active sprint, bumps the version (v0.1.N), updates the
changelog, tags, and pushes.
Manage the sprint lifecycle from main, or start sprint work on a team
branch. Use when the user says "start sprint", "start working on the
server/client/copy", "begin sprint", or invokes /start-sprint. On main:
assesses sprint state and does the next right thing (close, activate, or
guide). On a team branch: merges main, loads the briefing, presents the
work plan.
user-invocable: true
allowed-tools: Bash, Read, Grep, Glob, TeamCreate, Task, TaskCreate, TaskUpdate, TaskList, SendMessage, AskUserQuestion
---
@@ -32,12 +32,22 @@ the team branch workflow (steps 2–8).
---
## Main branch workflow (sprint close + version bump)
## Main branch workflow (sprint lifecycle management)
When `/start-sprint` is run on `main`, it means the user wants to close
the current sprint, cut a version, and prepare for the next one.
When `/start-sprint` is run on `main`, assess the current sprint state
and do the next right thing. Query the database to determine the state:
### M1. Close the active sprint
```bash
db/connectors/sqlite-query "SELECT id, name, status FROM sprints ORDER BY id DESC LIMIT 3"
```
Then follow the **first matching case**:
### Case A: An active sprint exists
The active sprint needs to be closed before moving on.
#### A1. Close the active sprint
```bash
db/connectors/sprint stop
@@ -46,11 +56,17 @@ db/connectors/sprint stop
This marks the active sprint as completed and lists carry-over candidates.
Note the sprint number (N) from the output.
### M2. Bump the version
#### A2. Bump the version
The project version scheme is `v0.1.{sprint_number}`. After closing
sprint N, the version is `v0.1.N`.
Update `project.yaml`:
- Set the `version` field to `0.1.N` (this is the source of truth).
Update `server/Cargo.toml`:
- Set `version = "0.1.N"` in `[package]`.
Update `CHANGELOG.md`:
- Move all entries under `## [Unreleased]` into a new section
`## [v0.1.N] — YYYY-MM-DD` (using today's date).
@@ -58,32 +74,66 @@ Update `CHANGELOG.md`:
- Keep the existing sub-headings (Added, Fixed, Changed, Removed) —
only move entries that have content.
### M3. Commit the release
#### A3. Commit the release
Stage and commit `CHANGELOG.md`:
Stage and commit `project.yaml`, `server/Cargo.toml`, and `CHANGELOG.md`:
```
chore(meta): release v0.1.N
```
### M4. Tag the release
#### A4. Tag the release
```bash
git tag v0.1.N
```
### M5. Push
#### A5. Push
```bash
git push && git push --tags
```
### M6. Report
#### A6. Check for a planned sprint
Output a summary:
- Sprint closed (name, done/total tickets, carry-over count)
- Version tagged (`v0.1.N`)
- Carry-over candidates (if any)
- Suggest running `/plan-sprint` next to prepare the next sprint
After closing, re-query the database. If a sprint in `planning` status
exists, continue to **Case B**. Otherwise, report the close and suggest
running `/plan-sprint`.
---
### Case B: No active sprint, but a planned sprint exists
A sprint is ready to activate. Verify it looks complete:
1. Check that briefing files exist at `docs/sprints/sprint-N/`:
```bash
ls docs/sprints/sprint-N/
```
2. Check the ticket count:
```bash
db/connectors/sprint status --sprint N
```
If briefings are missing or the sprint has 0 tickets, report the gap
and suggest running `/plan-sprint` to complete planning.
If everything looks ready, activate the sprint:
```bash
db/connectors/sprint start
```
Then report:
- Sprint activated (name, ticket count per team)
- Remind the user to switch to a team branch and run `/start-sprint`
there (or `cd` into the relevant worktree)
---
### Case C: No active sprint and no planned sprint
Nothing is ready. Report the state and suggest running `/plan-sprint`
to plan the next sprint.
---
+8
View File
@@ -6,6 +6,14 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased]
### Added
- `project.yaml` — technical project descriptor with version, architecture, simulation, and content model as the canonical version source of truth
- Scratchpad: asset generation pipeline idea (registry, status tracking, prompt versioning, pre-sprint cohesion)
- Scratchpad: remote terminal proxy idea for mobile monitoring of Claude Code permission prompts and interactive elements
### Changed
- `push-pr` skill now runs `/commit` first when uncommitted changes are detected
## [v0.1.9] — 2026-02-18
### Fixed
+2 -1
View File
@@ -3,7 +3,8 @@
A top-down immersive sim — occlusion-based detective game with combat elements, set in an original science fiction universe. Single-character perspective, asymmetric information as core mechanic, Rimworld-style storyteller. Godot 4 client + Rust/bevy_ecs simulation server via subprocess/IPC (D-020).
**Official Title:** The Settled Reach (D-021)
**Repository name:** commonwealth (historical code name, retained for path stability)
**Repository name:** settled-reach (formerly commonwealth, renamed for clarity)
**Version source of truth:** `project.yaml` (root `version` field, scheme: `0.1.{sprint_number}`)
## Project Structure
+12
View File
@@ -7,4 +7,16 @@ Personal notes and random thoughts. Not acted upon unless explicitly instructed.
- Pipeline to create postcards for each world — visuals for in-game dossiers
- Investigate using Veo to create gate transition movies — based on planetary profiles, postcards, and game visual style
- Capture discussion with Gemini about setting up a 3D to 2D pipeline
- Improve asset generation pipeline: proper asset registry, status tracking per asset, prompt storage/versioning, pre-sprint prompt preparation pass to maintain visual/audio cohesion across batches
- Remote terminal proxy for Claude Code — mobile notification + interaction bridge for monitoring progress away from desk. Full feature scope:
- Capture permission prompts across all terminals/worktrees in a project
- Push notifications to phone (Ntfy/Gotify/Pushover/custom — self-hostable)
- Summary of last assistant message for context (what Claude is doing and why it's asking)
- Support AskUserQuestion mode: render multiple-choice options, free-text input
- Support permission approve/deny with the tool call details
- Basically a full terminal proxy that adapts to Claude Code's interactive elements
- Starting point: peon-ping already hooks into the right events (PermissionRequest, Notification, Stop, etc.) via ~/.claude/hooks/
- Hook event JSON includes: hook_event_name, notification_type, session_id, cwd, permission_mode
- Gap: hook event data may not include prompt content (tool call details, AskUser question text, multiple choice options) — investigate what's in the full event payload
- Architecture: extend peon-ping's send_notification pattern to push to a remote service, add a response channel back to the terminal
+83
View File
@@ -0,0 +1,83 @@
# Sprint 10: Prove — Audio Tasks
**Goal:** Expand the Gauntlet test suite with new rooms and cross-room scenarios, wire the audio architecture end-to-end, and complete client UX polish from Sprint 9 carry-overs — proving the full system holds together.
**Branch:** `audio`
**Agents:** Inigo (sound design)
---
## New Tickets
| # | Title | Blocked by |
|---|-------|------------|
| #327 | Audio asset set — 8 minimum viable files via Stable Audio Open | — |
Use `db/connectors/ticket show <id>` for full details.
---
## Key Decisions
- `decisions/scope.md` — D-038 (audio in v0.1 — 8 files spec, hybrid generation approach)
- `decisions/perception.md` — D-067 (recognition chime fires at onset of cognitive delay), D-069 (audio dip profiles), D-071 (ListeningFocus boost), D-072 (universal event-driven conversation murmur)
- `decisions/architecture.md` — D-068 (5-bus audio architecture), D-073 (zone crossfade)
- `decisions/content.md` — D-074 (audio aesthetic identity — insert-tech vs organic)
---
## Notes
**#327 — Audio asset set — 8 minimum viable files**
- Existing: `AudioManager` autoload at `client/scripts/autoloads/audio_manager.gd` is fully implemented (D-068). The directory-scan registry pattern is in place — drop OGG files into `res://audio/` and they register automatically. Sprint 9 delivered 6 interaction SFX and 2 revised monologue chimes (#440, #453).
- What this ticket adds: The 8 ambient and world-SFX assets specified in D-038. These are distinct from the Sprint 9 interaction sounds — they cover the continuous soundscape and footstep system.
**The 8 files (D-038):**
| Key | File | Duration | Bus | Method |
|-----|------|----------|-----|--------|
| `amb_station_base` | `amb_station_base.ogg` | 60-90s | Ambient | SAO — station hum + span gate vibration |
| `amb_workplace_layer` | `amb_workplace_layer.ogg` | 45-60s | Ambient | SAO — cargo machinery |
| `amb_bar_layer` | `amb_bar_layer.ogg` | 45-60s | Ambient | SAO — conversation murmur baked in |
| `amb_corridor_layer` | `amb_corridor_layer.ogg` | 45-60s | Ambient | SAO — ventilation/subtle hum |
| `sfx_footstep_metal_walk` | `sfx_footstep_metal_walk.ogg` | 0.2-0.3s | WorldSFX | SAO or manual — one footstep, walk cadence |
| `sfx_footstep_metal_run` | `sfx_footstep_metal_run.ogg` | 0.2-0.3s | WorldSFX | SAO or manual — one footstep, run cadence |
| `sfx_monologue_chime` | `sfx_monologue_chime.ogg` | 0.5-1.0s | UISounds | Manual synthesis — crystalline, neural-lattice feel |
| `sfx_monologue_chime_urgent` | `sfx_monologue_chime_urgent.ogg` | 0.5-1.0s | UISounds | Manual synthesis — sharper, contradiction/anomaly variant |
**D-074 aesthetic split — critical:**
- Ambient layers and footsteps = **organic**: warm, breathy, environmental reverb, natural decay. Use SAO for these.
- Monologue chimes = **insert-tech**: synthetic, precise, clinical, no reverb. Manually synthesize — SAO will produce too organic a character for chimes.
- The Sprint 9 chimes (#453) are acknowledged placeholders. Sprint 10 chimes are the production-quality replacements.
**D-038 amendment (hybrid approach):**
- SAO ceiling is ~47s. Accept 45s loops with crossfade for ambient layers (the `play_loop` method in AudioManager handles this).
- Sounds <200ms with precise/digital character: manual synthesis only.
**Zone crossfade integration:**
- `AudioManager.set_zone()` is currently a stub (D-073). This sprint's audio assets enable testing the stub's behavior. Inigo should verify that `amb_station_base`, `amb_workplace_layer`, `amb_bar_layer`, and `amb_corridor_layer` all loop cleanly with no audible seam — AudioManager's `_enable_loop` will set `loop = true` on OGG streams automatically.
- Full zone crossfade logic (the tween between ambient layers on zone change) is NOT in scope for this sprint — it remains a stub. The assets just need to be present and looping.
**Delivery:**
- Commit all 8 OGG files to `audio` branch under `client/audio/` (which maps to `res://audio/` in Godot).
- AudioManager registers them at startup via directory scan. No code changes to client branch.
- Effort: 3-4d (generation + iteration + mastering).
---
## Dependency Chain
```
#327 (8 audio assets) — standalone; AudioManager stub (D-068) already in client branch
```
---
## 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(audio): sprint 10 prove — ambient + world sfx assets" --description "body" --base main --head audio
```
+68
View File
@@ -0,0 +1,68 @@
# Sprint 10: Prove — CI Tasks
**Goal:** Expand the Gauntlet test suite with new rooms and cross-room scenarios, wire the audio architecture end-to-end, and complete client UX polish from Sprint 9 carry-overs — proving the full system holds together.
**Branch:** `ci`
**Agents:** Justine (build/deploy), Hoshe (QA review)
---
## New Tickets
| # | Title | Blocked by |
|---|-------|------------|
| #499 | Performance baseline tooling (make perf-baseline) | #487 (done) |
| #510 | CI pipeline (Gitea Actions YAML, 3-tier) | — |
| #515 | Bidirectional relationship consistency warning (content validation check 9) | #464 (done) |
Use `db/connectors/ticket show <id>` for full details.
---
## Key Decisions
- `decisions/architecture.md` — D-030 (testing architecture phases), D-026 (100ms tick budget)
- `decisions/scope.md` — D-038 (audio in v0.1 — audio asset presence/absence affects `make ci` behavior)
---
## Notes
**#499 — Performance baseline tooling**
- Existing: `Makefile` has `make pre-pr`, `make test-server`, `make test-client` targets. The test infrastructure (Sprint 9) is complete. No `perf-baseline` target exists yet.
- Deliver: `make perf-baseline` target. Runs the server benchmark suite, captures tick timing, memory usage, and entity count scaling metrics, outputs results to `tests/perf/`. The baseline file should be committed and tracked in git so future runs can detect regressions.
- Integration: Server #500 (content scaling test) feeds into this — coordinate timing so #499 can include the content scaling numbers in the baseline output. If #500 isn't merged, the perf baseline can run with existing content and be updated when #500 lands.
**#510 — CI pipeline (Gitea Actions YAML, 3-tier)**
- Existing: `make pre-pr` exists and is the manual gate. Gitea Actions self-hosted runner is available.
- Deliver: A Gitea Actions workflow YAML (`/.gitea/workflows/ci.yaml` or `.gitea/workflows/`) implementing three tiers:
- Commit tier: `<2min` — lint only (`make lint-server`, `make lint-client`)
- PR merge gate: `<15min` — wraps `make pre-pr`
- Nightly: `<30min` — full build + all tests + content validation
- **Deferred condition**: This ticket is backlog-tagged "deferred until lead greenlights." Confirm with Team Leader before starting. If greenlit, coordinate with Tyre on self-hosted runner configuration.
- Integration: Wraps existing `make` targets — should require zero changes to those targets.
**#515 — Bidirectional relationship consistency warning**
- Existing: Content validation runs via `tooling/validate-content`. Phase 1-2 checks are complete (#464 done). Check 9 is advisory.
- Deliver: Advisory warning (non-blocking, not an error) when NPC A has a relationship to NPC B but no reciprocal entry exists in NPC B's relationships. Output format: `WARN: NPC 'kael' has relationship to 'sera' but 'sera' has no reciprocal entry.` Effort: 0.25d.
- Non-obvious: One-sided relationships are sometimes intentional (faction member knows of faction leader, not vice versa). The warning is advisory, never a hard failure.
---
## Dependency Chain
```
#499 (perf baseline) — standalone (server #487 done); benefits from server #500 merging first
#510 (CI pipeline) — standalone; greenlight from lead required before start
#515 (bidirectional warning) — standalone (#464 done)
```
---
## 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(ci): sprint 10 prove — ci" --description "body" --base main --head ci
```
+109
View File
@@ -0,0 +1,109 @@
# Sprint 10: Prove — Client Tasks
**Goal:** Expand the Gauntlet test suite with new rooms and cross-room scenarios, wire the audio architecture end-to-end, and complete client UX polish from Sprint 9 carry-overs — proving the full system holds together.
**Branch:** `client`
**Agents:** Stig (UI/client dev), Tyre (arch review), Hoshe (QA)
---
## Carry-over from Sprint 9
| # | Title | Status | Notes |
|---|-------|--------|-------|
| #501 | Hub teleport client UX (Home key, fade transition) | backlog | Targeted Sprint 9, slipped — blocked by #491 server work which also slipped. Unblocks immediately once server #491 ships. |
| #502 | Room reset client UX (reset plate tile, interaction verb, amber flash) | backlog | Targeted Sprint 9, slipped. Unblocked (#490 done). |
| #503 | Auto-checklist progress tracking (client-side snapshot evaluation) | backlog | Targeted Sprint 9, slipped. Unblocked (#497 done). |
---
## New Tickets
| # | Title | Blocked by |
|---|-------|------------|
| #501 | Hub teleport client UX (Home key, fade transition) | #491 server (Sprint 10) |
| #502 | Room reset client UX (reset plate tile, interaction verb, amber flash) | #490 (done) |
| #503 | Auto-checklist progress tracking (client-side snapshot evaluation) | #497 (done) |
| #517 | Introduce Michroma as game font | — |
| #526 | Client: mouse-relative facing and movement (D-054) | — |
| #518 | Client: wire insert open/close to PauseSimulation command | — |
| #521 | Confrontation D-033 color shift — client-side entity tint | #520 server (Sprint 10) |
Use `db/connectors/ticket show <id>` for full details.
---
## Key Decisions
- `decisions/architecture.md` — D-020 (Godot/Rust IPC), D-054 (mouse-relative facing), D-058 (auto-pause on insert open), D-066 (dual-scale grid)
- `decisions/perception.md` — D-033 (entity color = relationship to player), D-056 (insert diegetic visibility), D-057 (interaction verbs), D-060 (cognitive delay), D-063 (confrontation same box)
- `decisions/scope.md` — D-053 (movement stance toggle)
---
## Open Questions to Resolve Early
- **Q-019 (partial): Client-side entity lifecycle / StableId mapping** — #521 reads relationship state from `ObserverSnapshot` and adjusts entity tint. Confirm with server team that relationship state is included in the snapshot before #521 starts. Resolve before #521 begins.
---
## Notes
**#501 — Hub teleport client UX**
- Existing: `client/scripts/protocol/protocol.gd` handles PlayerAction serialization. `client/scripts/rendering/world_renderer.gd` handles camera.
- Deliver: Home key sends `PlayerAction::TeleportToHub`. On receipt: instant camera snap to hub spawn position + 0.3s fade-to-black-and-back tween. Effort: 0.5d. Gauntlet-mode only guard matches server behavior.
- Dependency: Wait for server #491 to merge before testing end-to-end. Can develop and unit-test client logic in isolation using local bridge stub.
**#502 — Room reset client UX**
- Existing: `client/scripts/rendering/tile_renderer.gd` handles tile visual overrides. Interaction verbs rendered by UI layer.
- Deliver: (1) `reset_plate` tile type renders with amber color override. (2) 'Reset Room' verb appears when player faces reset plate. (3) On reset confirmation: 0.15s amber flash + monologue "Systems recalibrated." fires via monologue event. Effort: 0.5d.
- Integration: Server #490 (done) already emits the reset event. Client just needs to consume it.
**#503 — Auto-checklist progress tracking**
- Existing: Checklist YAML schema defined by CI #497 (done). The test client handles its own evaluation separately.
- Deliver: Client evaluates `ObserverSnapshot` against loaded checklist YAML conditions, auto-tracks verification items with a Gauntlet-mode HUD overlay. Full tracking in test-client-only mode; lightweight overlay in Godot per R2-OQ-06. Effort: 1.5d.
- Integration: Test-client-only overlay — does not affect production game HUD. Coordinate with Hoshe on checklist condition format.
**#517 — Michroma font**
- Existing: Default Godot font throughout client UI. No font assets committed yet.
- Deliver: Download Michroma from Google Fonts (OFL license), commit to `client/assets/fonts/`. Update all Label, RichTextLabel, and LineEdit nodes to use Michroma. Acceptance: font renders legibly in HUD, dialogue box, and debug overlay at game resolution. Effort: 0.5d. Purely cosmetic — no logic changes.
- Non-obvious: Michroma is geometric sans-serif at display weights — confirm legibility at small sizes (sub-16px tooltip text) before committing globally. Consider a size floor.
**#526 — Mouse-relative facing and movement**
- Existing: `client/scripts/main.gd` handles input. WASD currently uses fixed cardinal directions. `client/scripts/protocol/protocol.gd` sends facing octant to server.
- Deliver: Mouse position determines facing direction (client-side float computed from player screen position to cursor). WASD movement becomes mouse-relative (forward = toward cursor). Server receives facing octant only, unchanged interface. Effort: 1d.
- Key decision: D-054 — mouse facing is purely client-side. Server only ever sees the octant. The full float stays in the client for rendering purposes.
**#518 — Wire insert open/close to PauseSimulation**
- Existing: Server pause system at 50%/0% tick rate exists (#406, done). `client/scripts/autoloads/sim_bridge.gd` handles server commands. Insert UI open/close events are in `client/scripts/main.gd`.
- Deliver: When insert UI opens, client sends `PauseSimulation` command. When it closes, client sends `ResumeSimulation`. D-058 confirms auto-pause in SP mode. Ticket #448 was cancelled before client wiring was completed. Effort: 0.5d.
- Non-obvious: The pause/resume must be idempotent — if the server is already paused (e.g. Gauntlet room interlude), opening the insert should not double-pause.
**#521 — Confrontation D-033 color shift**
- Existing: `client/scripts/rendering/entity_renderer.gd` applies D-033 relationship colors. `ObserverSnapshot` carries entity relationship state.
- Deliver: On confrontation delivery (server #520 decrements relationship state), entity renderer fades the entity's D-033 tint toward the new relationship color using a 0.5-1s tween. Not an instant flip — a fade that the player perceives as "something changed."
- Dependency: Blocked by server #520. Start after #520 merges.
---
## Dependency Chain
```
#502 (room reset UX) — standalone (server #490 done)
#503 (auto-checklist) — standalone (CI #497 done)
#517 (Michroma font) — standalone, parallel
#518 (insert pause wire) — standalone, parallel
#526 (mouse-relative facing) — standalone, parallel
Server #491 (hub teleport) → #501 (hub teleport UX)
Server #520 (confrontation response) → #521 (D-033 color shift)
```
---
## 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 10 prove — client" --description "body" --base main --head client
```
+167
View File
@@ -0,0 +1,167 @@
# Sprint 10: Prove — Joint / Integration
**Goal:** Expand the Gauntlet test suite with new rooms and cross-room scenarios, wire the audio architecture end-to-end, and complete client UX polish from Sprint 9 carry-overs — proving the full system holds together.
**Agents:** All implementation agents (Dudley, Stig, Hoshe, Tyre, Justine, Inigo)
---
## Pre-Sprint Decisions
No new decisions are required before Sprint 10 begins. All sprint tickets operate within confirmed decisions. Items to monitor:
| Item | Status | Needed by |
|------|--------|-----------|
| Relationship state in ObserverSnapshot | Confirm with server team that relationship state is carried per entity in the snapshot (Q-019 partial resolution) | #521 (D-033 color shift, client) |
| CI pipeline greenlight | Team Leader must confirm before #510 starts | #510 (Gitea Actions YAML, CI) |
| Server #491 merge timing | Client #501 is blocked on it — server should prioritize #491 in the first half of sprint | #501 (hub teleport UX, client) |
| Server #520 merge timing | Client #521 is blocked on it — server should ship #520 before sprint midpoint | #521 (confrontation color shift, client) |
---
## Cross-Team Dependencies
```
Server #491 (hub teleport action)
→ Client #501 (hub teleport UX — Home key + fade)
Server #520 (confrontation world response)
→ Client #521 (D-033 color shift on confrontation)
Server #500 (content scaling test)
→ CI #499 (perf baseline — benefits from #500 data)
Server #498 (Gauntlet rooms 4-7)
→ #506 (cross-room transitions, deferred to Sprint 11)
Server #483 (replay loading)
→ Scripted Gauntlet testing (unblocks Sprint 11 automation)
Audio #327 (8 ambient + SFX assets)
→ Client AudioManager (automatic registration via directory scan — no client code change)
→ D-073 zone crossfade stub can be tested with real assets for the first time
```
**Critical path:** `Server #491 → Client #501` and `Server #520 → Client #521`. Both server tickets need to merge before sprint midpoint to give client time to complete their dependent work.
---
## Sprint Completion Proof
Sprint 10 is complete when all of the following are observable:
**Hub teleport**
- Pressing Home key in Gauntlet mode sends `TeleportToHub`, player entity moves to hub spawn tile
- 0.3s fade-to-black-and-back plays on teleport
- Dialogue/monologue/interaction buffer is cleared on teleport
- Non-Gauntlet maps: action is rejected server-side with log warning; client shows no effect
**Room reset UX**
- `reset_plate` tile type renders with amber color
- 'Reset Room' verb appears in interaction menu when player faces reset plate
- On reset: 0.15s amber flash + "Systems recalibrated." monologue line plays
**Auto-checklist tracking**
- In test-client mode: checklist YAML loads, client evaluates ObserverSnapshot against conditions, verified items tick off automatically in HUD overlay
- Checklist HUD is absent in non-test-client Godot mode
**Gauntlet expansion**
- Server boots with Gauntlet content and all 7 rooms (existing 3 + new 4) load without panic
- Room constants for all 4 new rooms in `server/src/test_world/constants.rs`
- Room reset works correctly in new rooms (entity positions and fog reset to tick-0 state)
**Content scaling**
- `make test-server` includes the content scaling test: baseline run passes, extra-NPC comparative run stays within D-026 tick budget
**Performance baseline**
- `make perf-baseline` runs without error and produces `tests/perf/baseline.json` (or equivalent)
- Baseline file committed to repo
**Replay loading**
- `tooling/test-client --replay <file.jsonl>` loads the file and sends PlayerInput at correct tick timing against a live server
**Client UX polish**
- Michroma font renders in all Labels/RichTextLabels in HUD and dialogue box
- WASD movement is mouse-relative (forward = toward cursor direction)
- Insert open sends `PauseSimulation`, insert close sends `ResumeSimulation`
**Confrontation system**
- Confrontation delivery: target NPC shifts to Tier 2 animation, relationship state decrements, monologue spike fires (server)
- Client: entity D-033 tint fades to new relationship color over 0.5-1s on confrontation delivery
**Audio**
- 8 OGG files present in `audio` branch under `client/audio/`
- `AudioManager` registers all 8 at startup (log output confirms count)
- Ambient loops play without audible seam
- Monologue chimes have no reverb (insert-tech aesthetic per D-074)
**CI (if greenlit)**
- Gitea Actions YAML committed to `.gitea/workflows/`
- Commit tier runs in <2min on push
- PR merge gate wraps `make pre-pr` in <15min
---
## Test Plan Alignment (D-030)
| D-030 Phase | Coverage | Sprint 10 Status |
|-------------|----------|-----------------|
| Phase 1 (infra) | Done Sprints 1-2 | — |
| Phase 2 (integration) | Done Sprints 3-5 | — |
| Phase 3 (CauseChain, divergent snapshots) | Gauntlet golden suite (#485, Sprint 9) | Expanding with rooms 4-7 |
| Replay / scripted testing | #483 (test client replay loading) | In scope |
| Performance regression baseline | #499 (make perf-baseline) | In scope |
| Content scaling | #500 (baseline + NPC pack comparative) | In scope |
| Pre-PR gate | `make pre-pr` (Sprint 9, done) | Stable |
---
## Open Questions to Resolve Early
- **Q-019 (partial): Client-side entity StableId / relationship state in snapshot** — Client #521 needs relationship state per entity in ObserverSnapshot. Server team should confirm scope before #521 starts. No formal Q-NNN resolution required — just a server team confirmation.
- **CI pipeline greenlight (no Q-NNN)** — #510 has an explicit "deferred until lead greenlights" note. Team Leader to confirm before CI team starts that ticket.
---
## Sequence Recommendation
**Days 1-3 (all teams in parallel):**
- Server: start #491 immediately (no blockers). Priority — unblocks client #501.
- Server: start #483 (no blockers). `replay.rs` stub exists in `tooling/test-client/src/`.
- Server: start #498 (no blockers). 4 new Gauntlet rooms; follow existing room pattern.
- Server: start #514 (small, standalone).
- Server: start #519 (standalone, #427 done).
- Client: start #502 (no blockers, #490 done).
- Client: start #503 (no blockers, #497 done).
- Client: start #517 (standalone).
- Client: start #526 (standalone).
- Client: start #518 (standalone).
- CI: start #499 (no blockers, #487 done).
- CI: start #515 (standalone, #464 done).
- Audio: start #327.
**Days 4-6:**
- Server: start #520 (no blockers). Priority — unblocks client #521.
- Server: start #500 (no blockers, #489 done).
- Client: #501 unblocks once server #491 merges.
**Days 7-10:**
- Client: #521 unblocks once server #520 merges.
- CI: #510 starts only after lead greenlight (may be later in sprint or deferred).
- All teams: verification against Sprint Completion Proof criteria.
---
## PR Workflow
Each team submits their own PR from their branch. Integration is via merge to `main`. No joint branch — all tickets are single-team. The `joint.md` tracks integration readiness but does not produce a separate branch.
```bash
# Verify sprint assignment before PR
db/connectors/sprint status --team <team>
# Standard PR (all flags required — see CLAUDE.md)
tea pr create --repo jpmschweitzer/settled-reach --login schweitz \
--title "feat(<scope>): sprint 10 prove — <team summary>" \
--description "body" --base main --head <branch>
```
+103
View File
@@ -0,0 +1,103 @@
# Sprint 10: Prove — Server Tasks
**Goal:** Expand the Gauntlet test suite with new rooms and cross-room scenarios, wire the audio architecture end-to-end, and complete client UX polish from Sprint 9 carry-overs — proving the full system holds together.
**Branch:** `server`
**Agents:** Dudley (simulation), Tyre (arch review), Hoshe (QA)
---
## Carry-over from Sprint 9
| # | Title | Status | Notes |
|---|-------|--------|-------|
| #491 | Hub teleport action (PlayerAction::TeleportToHub) | backlog | Targeted for Sprint 9, slipped due to #487 dependency completing late. Unblocked as of sprint close. |
| #483 | Test client replay loading + tick-scheduled sending | backlog | Critical for scripted Gauntlet testing. Targeted Sprint 9, slipped. Unblocked (#480 done). |
| #500 | Content scaling test (baseline + extra NPC comparative) | backlog | Targeted Sprint 9, deferred. Unblocked (#489 done). |
---
## New Tickets
| # | Title | Blocked by |
|---|-------|------------|
| #491 | Hub teleport action (PlayerAction::TeleportToHub) | #487 (done) |
| #483 | Test client replay loading + tick-scheduled sending | #480 (done) |
| #498 | Gauntlet rooms 4-7 (Interaction Gallery, Fog Theater, Crowd Plaza, Dialogue Room) | #487 (done) |
| #500 | Content scaling test (baseline + extra NPC comparative) | #489 (done) |
| #514 | blocked_entities debug field on ObserverSnapshot | — |
| #519 | Walk-away NPC reaction — server-side Phase 2 (animation shift, routine change) | #427 (done) |
| #520 | Confrontation world response — server-side trigger | — |
Use `db/connectors/ticket show <id>` for full details.
---
## Key Decisions
- `decisions/architecture.md` — D-010 (deterministic simulation), D-026 (100ms tick budget), D-041 (knowledge graph data model)
- `decisions/perception.md` — D-059 (fog/shader five layers), D-060 (cognitive delay), D-063 (confrontation world response), D-064 (walk-away three phases)
- `decisions/scope.md` — D-038 (audio in v0.1 scope)
---
## Notes
**#491 — Hub teleport action**
- Existing: `server/src/test_world/rooms/hub.rs` for the hub spawn location. `PlayerAction` enum lives in `server/src/bridge/`.
- Deliver: `PlayerAction::TeleportToHub` variant. On receipt: move player entity to hub spawn tile, clear dialogue/monologue/interaction buffer. Does NOT affect room state, inventory, game time, or knowledge graph. Reject the action with a log warning on non-Gauntlet maps.
- Integration: Client #501 depends on this — ship it first half of sprint.
**#483 — Test client replay loading**
- Existing: `tooling/test-client/src/` has `main.rs`, `golden.rs`, `replay.rs` (stub). The `replay.rs` module exists but the loading logic was deferred.
- Deliver: Load a JSONL replay file (one JSON array per tick), send `PlayerInput` at correct tick timing. Target: `tooling/test-client/src/replay.rs`.
- Integration: Enables scripted Gauntlet testing end-to-end — unblocks the cross-room test scenarios in later sprints.
**#498 — Gauntlet rooms 4-7**
- Existing: `server/src/test_world/rooms/` has `hub.rs`, `inventory_warehouse.rs`, `occlusion_corridor.rs`, `pause_chamber.rs`. The `mod.rs` wires them together.
- Deliver: Four new rooms — Interaction Gallery (24x20, 5 entities, D-057), Fog Theater (44x32, 4 entities, D-059), Crowd Plaza (32x32, 15 entities), Dialogue Room (28x20, 4 entities, D-041). Follow the pattern of existing room modules. Each room must have constants in `server/src/test_world/constants.rs`.
- Integration: Unblocks #506 (cross-room transition tests) in a future sprint.
**#500 — Content scaling test**
- Existing: The baseline test infrastructure is in place post-#489. Content packs are in `server/src/content/`.
- Deliver: A test that runs the baseline NPC pack then the same scenario with additional NPCs, asserts tick timing stays within D-026 budget and behavior is unchanged for original NPCs.
- Integration: Feeds into CI perf baseline (#499) which CI team handles.
**#514 — blocked_entities debug field**
- Existing: `ObserverSnapshot` in `server/src/bridge/`. LOS computation is in `server/src/perception/`.
- Deliver: Add `blocked_entities: Vec<StableId>` (or `Option<Vec<StableId>>`) to `ObserverSnapshot`. Feasibility confirmed at ~300 tile lookups/tick (R2-OQ-05). Debug-only field; `#[serde(default)]` so client gracefully ignores on older snapshots.
- Integration: Improves test client debug output. Standalone, no cross-team dependency.
**#519 — Walk-away NPC reaction Phase 2**
- Existing: Phase 1 (client fade, #437) and Phase 3 (KG recording, #427) are done. Phase 2 is the missing server-side piece.
- Deliver: On `PlayerAction::WalkAway` (or dialogue exit event), server triggers: (1) target NPC shifts animation tier to Tier 2 (D-047), (2) NPC routine deviation is recorded in their state machine. D-064 Phase 2 scope.
- Integration: Standalone server-side work. No client changes required.
**#520 — Confrontation world response**
- Existing: Confrontation delivery is wired through dialogue system. D-063 specifies the world response.
- Deliver: On confrontation delivery: (1) target NPC shifts to Tier 2 animation (D-047 animated tier), (2) NPC relationship state decremented (affects D-033 color which client #521 renders), (3) monologue spike event emitted. Three separate effects, all server-authoritative.
- Integration: Client #521 blocked by this — complete #520 first half of sprint.
---
## Dependency Chain
```
#483 (replay loading) — standalone, parallel
#491 (hub teleport server) → #501 (hub teleport client UX, cross-team)
#498 (Gauntlet rooms 4-7) → #506 (cross-room transitions, future sprint)
#500 (content scaling) → #499 (perf baseline, CI team)
#514 (blocked_entities) — standalone, parallel
#519 (walk-away phase 2) — standalone, parallel
#520 (confrontation world response) → #521 (D-033 color shift, client team)
```
---
## 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): sprint 10 prove — server" --description "body" --base main --head server
```
+37
View File
@@ -0,0 +1,37 @@
name: The Settled Reach
version: 0.1.9
repository: settled-reach
codename: commonwealth
description: >
Top-down immersive sim with occlusion-based detection mechanics and
combat elements. Single-character perspective where asymmetric information
is the core gameplay mechanic. A Rimworld-style storyteller drives
emergent narrative across a detective-smuggler dual-lens campaign.
setting: >
Original science fiction universe — the Settled Reach, a network of
star systems connected by Founder Gates. Neural lattice technology
enables soft immortality, forking, and re-embodiment. The v0.1
vertical slice takes place in Sova Transit District, Krenn System.
architecture:
client: Godot 4 (GDScript)
server: Rust with bevy_ecs (simulation server)
transport: subprocess/IPC via TCP with MessagePack serialization
protocol: length-prefixed MessagePack frames (4-byte big-endian)
determinism: ChaCha20 seeded RNG, deterministic tick processing
simulation:
tick_rate: 10 ticks per game-minute
time_model: 4 day phases (Morning, Afternoon, Evening, Night)
grid: dual-scale (0.5m simulation tiles, 1m visual tiles)
visibility: symmetric shadowcasting + forward/peripheral/blind vision cone
knowledge: per-entity knowledge graphs with confidence decay
content:
format: YAML with JSON Schema validation
structure: campaigns/systems/stations/districts hierarchy
npcs: 10-axis model (7 essential + 3 supporting) with CombatCapability
dialogue: tagged line pools with 4-layer relational filtering
population: 30% flat / 50% mundane triangles / 20% intrigue-entangled
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "settled-reach-server"
version = "0.1.0"
version = "0.1.9"
edition = "2021"
[dependencies]