Compare commits
5
Commits
06aebccecc
...
a54a3a8100
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a54a3a8100 | ||
|
|
f160f07e6d | ||
|
|
c35248f103 | ||
|
|
7f97cb7ce3 | ||
|
|
d96a0599b6 |
@@ -149,14 +149,14 @@ Establish a list of reusable resources: scripts, references, and assets.
|
||||
|
||||
### Step 3: Initialize the Skill
|
||||
|
||||
Run the init script to generate a template skill directory:
|
||||
Create the skill directory manually:
|
||||
|
||||
```
|
||||
scripts/init_skill.py <skill-name> --path <output-directory>
|
||||
mkdir -p <output-directory>/<skill-name>
|
||||
```
|
||||
|
||||
Creates: skill directory, SKILL.md template with TODO placeholders, example
|
||||
resource directories with sample files.
|
||||
Then create `SKILL.md` with frontmatter and body. Add `scripts/`, `references/`,
|
||||
and `assets/` subdirectories only as needed.
|
||||
|
||||
Skip if iterating on an existing skill.
|
||||
|
||||
@@ -184,20 +184,14 @@ For design patterns, consult:
|
||||
|
||||
**Body:** Instructions for using the skill and its bundled resources.
|
||||
|
||||
### Step 5: Package the Skill
|
||||
### Step 5: Validate the Skill
|
||||
|
||||
```
|
||||
scripts/package_skill.py <path/to/skill-folder>
|
||||
```
|
||||
|
||||
Optional output directory:
|
||||
```
|
||||
scripts/package_skill.py <path/to/skill-folder> ./dist
|
||||
```
|
||||
|
||||
The script validates (frontmatter, naming, description, file organization) then
|
||||
packages into a `.skill` file (zip with .skill extension). Fix any validation
|
||||
errors and re-run if needed.
|
||||
Check the skill manually:
|
||||
- Frontmatter has `name` and `description`
|
||||
- SKILL.md body is under 500 lines
|
||||
- No extraneous files (README.md, CHANGELOG.md, etc.)
|
||||
- Scripts are executable and tested
|
||||
- References are referenced from SKILL.md
|
||||
|
||||
### Step 6: Iterate
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
name: plan-sprint
|
||||
description: >
|
||||
Plan the next sprint and generate team briefing files. Use when the user says
|
||||
"plan sprint", "prep sprint briefing", "plan next sprint", "sprint planning",
|
||||
or invokes /plan-sprint. Gathers current sprint status, scans the backlog,
|
||||
proposes ticket selection, and writes briefing files per team to
|
||||
docs/sprints/sprint-N/.
|
||||
user-invocable: true
|
||||
allowed-tools: Bash, Read, Grep, Glob, Write, AskUserQuestion
|
||||
---
|
||||
|
||||
# Plan Sprint
|
||||
|
||||
Generate sprint briefing files (`server.md`, `client.md`, `joint.md`) for the
|
||||
next sprint based on current project state.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Determine sprint number
|
||||
|
||||
```bash
|
||||
db/connectors/ticket sprint --active
|
||||
```
|
||||
|
||||
Next sprint = active sprint ID + 1. If no active sprint, ask the user.
|
||||
|
||||
### 2. Gather current sprint state
|
||||
|
||||
Review the active sprint for carry-overs:
|
||||
|
||||
```bash
|
||||
db/connectors/ticket list --sprint <current_id> --status in_progress
|
||||
db/connectors/ticket list --sprint <current_id> --status ready
|
||||
```
|
||||
|
||||
Any ticket not `done` is a potential carry-over. Note these for the briefing.
|
||||
|
||||
### 3. Scan the backlog
|
||||
|
||||
Pull candidate tickets by priority:
|
||||
|
||||
```bash
|
||||
db/connectors/ticket epics --status backlog
|
||||
```
|
||||
|
||||
For critical epics, check their children:
|
||||
|
||||
```bash
|
||||
db/connectors/ticket children <epic_id>
|
||||
```
|
||||
|
||||
Use `ticket show --brief <id> [<id>...]` to quickly scan multiple tickets.
|
||||
|
||||
### 4. Read existing code state
|
||||
|
||||
Scan what's already built to write accurate "what exists" notes:
|
||||
|
||||
```bash
|
||||
# Server modules
|
||||
ls server/src/ server/src/*/
|
||||
|
||||
# Client scripts
|
||||
ls client/scripts/ client/scripts/*/
|
||||
```
|
||||
|
||||
Read key files that sprint tickets will build on (bridge types, existing
|
||||
renderers, etc.) to reference specific integration points in the briefing.
|
||||
|
||||
### 5. Select tickets — propose to user
|
||||
|
||||
Based on the backlog scan, propose a sprint with:
|
||||
|
||||
- **Sprint theme** — a short name (Sprint 1 was "Run", Sprint 2 was "See")
|
||||
- **Sprint goal** — one sentence shared across all teams
|
||||
- **Server tickets** — stories from server-side epics
|
||||
- **Client tickets** — stories from client-side epics
|
||||
- **Joint tasks** — integration proofs, pre-sprint decisions, schema work
|
||||
|
||||
Present the proposal using AskUserQuestion for the user to approve or adjust.
|
||||
|
||||
Selection heuristics:
|
||||
- Follow dependency chains (don't pick a ticket if its blocker isn't in scope)
|
||||
- Respect D-030 test priority phases (sprint 1-2: infra, sprint 3-4: integration)
|
||||
- Mix carry-overs with new work
|
||||
- Aim for 3-6 tickets per team, with parallel tracks where possible
|
||||
- Check `decisions/questions.md` for open Q-NNN items that block candidates
|
||||
|
||||
### 6. Read relevant decisions
|
||||
|
||||
For the selected tickets, identify which `decisions/*.md` files are relevant.
|
||||
Read them to provide accurate cross-references in the briefing.
|
||||
|
||||
### 7. Write briefing files
|
||||
|
||||
Create `docs/sprints/sprint-N/` and write one file per team.
|
||||
|
||||
Read the template at `references/briefing-template.md` in this skill directory
|
||||
for the exact file structure.
|
||||
|
||||
Key requirements per file:
|
||||
- **server.md**: Carry-overs, new tickets, dependency chain, key decisions, notes
|
||||
referencing existing Rust modules by path
|
||||
- **client.md**: Same structure, notes referencing existing GDScript files by path
|
||||
- **joint.md**: Pre-sprint decisions table, integration tickets, sprint
|
||||
completion proof (concrete observable criteria), test plan alignment
|
||||
|
||||
### 8. Assign tickets to sprint in DB
|
||||
|
||||
After the user approves, assign all selected tickets to the new sprint:
|
||||
|
||||
```bash
|
||||
# Create the sprint
|
||||
db/connectors/sqlite-exec "INSERT INTO sprints (name, goal, status) VALUES ('Sprint N: Theme', 'goal', 'planned')"
|
||||
|
||||
# Assign tickets
|
||||
db/connectors/ticket sprint assign <ticket_id> <sprint_id>
|
||||
```
|
||||
|
||||
### 9. Present summary
|
||||
|
||||
Output:
|
||||
- Sprint number, theme, and goal
|
||||
- Ticket count per team
|
||||
- Carry-over count
|
||||
- Open questions that need early resolution
|
||||
- Files written
|
||||
@@ -0,0 +1,79 @@
|
||||
# Sprint Briefing Template
|
||||
|
||||
Each team gets one briefing file at `docs/sprints/sprint-N/<team>.md`.
|
||||
|
||||
## File structure
|
||||
|
||||
```markdown
|
||||
# Sprint N: <Theme> — <Team> Tasks
|
||||
|
||||
**Goal:** <One-sentence sprint goal, shared across all teams>
|
||||
|
||||
**Branch:** `<team>`
|
||||
**Agents:** <Agent names and roles>
|
||||
|
||||
## Carry-over from Sprint N-1
|
||||
|
||||
(Only if there are incomplete tickets from the previous sprint)
|
||||
|
||||
| # | Title | Status | Notes |
|
||||
|---|-------|--------|-------|
|
||||
| #ID | Title | status | Why it carried over |
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #ID | Title | #dependency or — |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/<domain>.md` — D-NNN (short name), D-NNN (short name)
|
||||
|
||||
## Open Questions to Resolve Early
|
||||
|
||||
(Only if there are Q-NNN items that block sprint tickets)
|
||||
|
||||
- **Q-NNN: Title** — Brief context. Resolve before #ID starts.
|
||||
|
||||
## Notes
|
||||
|
||||
One bullet per ticket with:
|
||||
- What exists already (files, modules, stubs)
|
||||
- What the ticket actually needs to deliver
|
||||
- Integration points with other tickets
|
||||
- Non-obvious gotchas
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#A (name) → #B (name) → #C (name)
|
||||
#D (name) → standalone, parallel track
|
||||
```
|
||||
|
||||
## 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(<scope>): description" --description "body" --base main --head <branch>
|
||||
\```
|
||||
```
|
||||
|
||||
## Joint briefing extras
|
||||
|
||||
The `joint.md` file additionally includes:
|
||||
|
||||
- **Pre-Sprint** table: decisions/schema work that must happen before implementation
|
||||
- **Sprint Completion Proof**: concrete observable criteria (what you can see/do when the sprint is done)
|
||||
- **Test plan** alignment with D-030 phases
|
||||
|
||||
## Team assignments
|
||||
|
||||
| Team | Branch | Agents | Scope |
|
||||
|------|--------|--------|-------|
|
||||
| server | `server` | Dudley (simulation), Oscar (networking) | Rust/bevy_ecs simulation |
|
||||
| client | `client` | Stig (UI), Oscar (networking) | Godot client rendering |
|
||||
| joint | both | All implementation agents | Integration, proofs, cross-team schema |
|
||||
| content | (none) | Mellanie, Paula, Miri, Araminta | Content authoring, no code branch |
|
||||
@@ -7,6 +7,9 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Sprint 2 "See" briefings (server, client, joint) — fog of perception through the bridge
|
||||
- `/plan-sprint` skill — automates sprint planning workflow and briefing file generation
|
||||
- `ticket show` multi-ID support and `--brief` flag for compact human-readable output
|
||||
- Q-018 through Q-023 — 6 open questions from architecture audit (shadowcasting, entity ID stability, collision resolution, tick overflow, pathfinding cache, debug visualization)
|
||||
- 5 architecture spike workshop briefs (knowledge graph, observer pipeline, NPC AI state machines, save/load, map authoring)
|
||||
- 17 tickets from architecture audit (#339-#355) — 7 Sprint 1 tasks, 5 Sprint 2+ tasks, 5 workshop epics
|
||||
@@ -116,6 +119,7 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
|
||||
- Rejected alternatives R-004 through R-010 documented (pure Bevy, pure Godot, GDExtension, C++ GDExtension, Fyrox, custom framework, protobuf)
|
||||
|
||||
### Fixed
|
||||
- create-skill references to nonexistent init_skill.py and package_skill.py scripts
|
||||
- Wire format mismatch: LocalBridge now uses rmp_serde::to_vec_named() (named maps) matching client Protocol.gd expectations
|
||||
- EOF on bridge read now returns BridgeError::Transport for disconnect detection instead of empty Vec
|
||||
- WalkabilityMap rewritten from flat Vec to chunk-based HashMap per D-012 architecture (Tyre review)
|
||||
|
||||
+72
-26
@@ -141,28 +141,72 @@ def cmd_list(conn, args):
|
||||
out({"ok": True, "count": len(rows), "rows": rows})
|
||||
|
||||
|
||||
def cmd_show(conn, ticket_id):
|
||||
rows = query(conn, """SELECT t.*, p.title as parent_title
|
||||
FROM tickets t LEFT JOIN tickets p ON t.parent_id = p.id
|
||||
WHERE t.id = ?""", (ticket_id,))
|
||||
if not rows:
|
||||
out({"ok": False, "error": f"Ticket #{ticket_id} not found"})
|
||||
return
|
||||
ticket = rows[0]
|
||||
# Get children
|
||||
children = query(conn, "SELECT id, title, status, priority FROM tickets WHERE parent_id = ? ORDER BY id", (ticket_id,))
|
||||
# Get dependencies (what blocks this)
|
||||
blockers = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d
|
||||
JOIN tickets t ON d.blocker_id = t.id
|
||||
WHERE d.blocked_id = ?""", (ticket_id,))
|
||||
# Get dependents (what this blocks)
|
||||
blocks = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d
|
||||
JOIN tickets t ON d.blocked_id = t.id
|
||||
WHERE d.blocker_id = ?""", (ticket_id,))
|
||||
ticket["children"] = children
|
||||
ticket["blocked_by"] = blockers
|
||||
ticket["blocks"] = blocks
|
||||
out({"ok": True, "ticket": ticket})
|
||||
def cmd_show(conn, ids, brief=False):
|
||||
tickets = []
|
||||
for ticket_id in ids:
|
||||
rows = query(conn, """SELECT t.*, p.title as parent_title
|
||||
FROM tickets t LEFT JOIN tickets p ON t.parent_id = p.id
|
||||
WHERE t.id = ?""", (ticket_id,))
|
||||
if not rows:
|
||||
tickets.append({"id": ticket_id, "error": f"Ticket #{ticket_id} not found"})
|
||||
continue
|
||||
ticket = rows[0]
|
||||
# Get children
|
||||
children = query(conn, "SELECT id, title, status, priority FROM tickets WHERE parent_id = ? ORDER BY id", (ticket_id,))
|
||||
# Get dependencies (what blocks this)
|
||||
blockers = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d
|
||||
JOIN tickets t ON d.blocker_id = t.id
|
||||
WHERE d.blocked_id = ?""", (ticket_id,))
|
||||
# Get dependents (what this blocks)
|
||||
blocks = query(conn, """SELECT t.id, t.title, t.status FROM ticket_deps d
|
||||
JOIN tickets t ON d.blocked_id = t.id
|
||||
WHERE d.blocker_id = ?""", (ticket_id,))
|
||||
ticket["children"] = children
|
||||
ticket["blocked_by"] = blockers
|
||||
ticket["blocks"] = blocks
|
||||
tickets.append(ticket)
|
||||
if brief:
|
||||
_print_brief(tickets)
|
||||
elif len(tickets) == 1:
|
||||
out({"ok": True, "ticket": tickets[0]})
|
||||
else:
|
||||
out({"ok": True, "count": len(tickets), "tickets": tickets})
|
||||
|
||||
|
||||
def _print_brief(tickets):
|
||||
for i, t in enumerate(tickets):
|
||||
if "error" in t:
|
||||
print(f"#{t['id']}: NOT FOUND")
|
||||
continue
|
||||
# Header line
|
||||
print(f"#{t['id']}: {t['title']}")
|
||||
# Metadata line
|
||||
parts = [f"{t['type']}", f"P:{t['priority']}", f"S:{t['status']}"]
|
||||
if t.get("assigned_to"):
|
||||
parts.append(f"@{t['assigned_to']}")
|
||||
if t.get("parent_id"):
|
||||
parts.append(f"Epic:#{t['parent_id']} ({t.get('parent_title', '?')})")
|
||||
if t.get("sprint_id"):
|
||||
parts.append(f"Sprint:{t['sprint_id']}")
|
||||
if t.get("decision_ref"):
|
||||
parts.append(f"Ref:{t['decision_ref']}")
|
||||
print(f" {' | '.join(parts)}")
|
||||
# Description
|
||||
desc = t.get("description") or ""
|
||||
if desc:
|
||||
# Truncate long descriptions
|
||||
if len(desc) > 200:
|
||||
desc = desc[:197] + "..."
|
||||
print(f" {desc}")
|
||||
# Dependencies
|
||||
if t.get("blocked_by"):
|
||||
blockers = ", ".join(f"#{b['id']} ({b['status']})" for b in t["blocked_by"])
|
||||
print(f" Blocked by: {blockers}")
|
||||
if t.get("blocks"):
|
||||
blocks = ", ".join(f"#{b['id']}" for b in t["blocks"])
|
||||
print(f" Blocks: {blocks}")
|
||||
if i < len(tickets) - 1:
|
||||
print()
|
||||
|
||||
|
||||
def cmd_done(conn, ids):
|
||||
@@ -286,7 +330,7 @@ HELP = """ticket — project ticket CLI
|
||||
|
||||
Usage:
|
||||
ticket list [--status S] [--priority P] [--epic N] [--sprint N] [--assigned A]
|
||||
ticket show <id> Full ticket detail with deps and children
|
||||
ticket show [--brief] <id> [<id>...] Full ticket detail (--brief for summary)
|
||||
ticket done <id> [<id> ...] Mark tickets as done
|
||||
ticket status <id> <new_status> Change ticket status
|
||||
ticket assign <id> <agent> Assign ticket to agent/branch
|
||||
@@ -320,10 +364,12 @@ def main():
|
||||
if cmd == "list":
|
||||
cmd_list(conn, args)
|
||||
elif cmd == "show":
|
||||
if not args:
|
||||
out({"ok": False, "error": "Usage: ticket show <id>"})
|
||||
brief = "--brief" in args
|
||||
id_args = [a for a in args if a != "--brief"]
|
||||
if not id_args:
|
||||
out({"ok": False, "error": "Usage: ticket show [--brief] <id> [<id> ...]"})
|
||||
else:
|
||||
cmd_show(conn, int(args[0]))
|
||||
cmd_show(conn, [int(a) for a in id_args], brief=brief)
|
||||
elif cmd == "done":
|
||||
if not args:
|
||||
out({"ok": False, "error": "Usage: ticket done <id> [<id> ...]"})
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Sprint 2: See — Client Tasks
|
||||
|
||||
**Goal:** Fog of perception working through the bridge — server computes LOS visibility, client renders fog.
|
||||
|
||||
**Branch:** `client`
|
||||
**Agents:** Stig (UI), Oscar (networking)
|
||||
|
||||
## Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #116 | Camera lock to character | — |
|
||||
| #129 | Tile rendering engine | — |
|
||||
| #130 | Entity sprite management | — |
|
||||
| #131 | Fog overlay rendering | #129 (needs tile layer to overlay) |
|
||||
| #113 | Fog rendering - client | #131 (rendering layer), server #112 (fog data in snapshot) |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/perception.md` — D-015 (camera locked, no panning), D-011 (fog of perception), D-019 (top-down camera)
|
||||
- `decisions/architecture.md` — D-020 (ObserverSnapshot drives all rendering)
|
||||
- `decisions/scope.md` — D-014 (v0.1 map spec: ~150x150, 2-3 z-levels, fog + LOS)
|
||||
|
||||
## Notes
|
||||
|
||||
- **#116:** Camera follows player character position. No panning, no rotation (v0.1). The `GameState.player_position` already tracks position — camera just needs to center on it smoothly. Use `Camera2D` with smoothing. Existing `main.gd` handles input; camera attaches to the player entity's position.
|
||||
- **#129:** Multi-layer tilemap rendering from snapshot data. Currently the client renders entities as `ColorRect` placeholders (`client/scripts/rendering/entity_renderer.gd`). This ticket adds a `TileMapLayer` (or multiple layers) for floor/walls/objects. Tiles come from the `ObserverSnapshot` — the client draws what the server says is visible. Placeholder art: colored rectangles with labels (D-014: "functional boxes with labels").
|
||||
- **#130:** Upgrade entity rendering from `ColorRect` to proper sprite management. Animation states (idle, walk). Entity color based on relationship state (D-033: unknown=teal, known=green, POI=amber, hostile=red). Facing direction indicator. Builds on existing `entity_renderer.gd`.
|
||||
- **#131:** Fog overlay on the tile layer. Three visibility states: visible (clear), fog-edge (dimmed), hidden (dark/black). Driven by `visible_tiles` data from `ObserverSnapshot`. This is the rendering half of the fog system — the server (#112) determines what's visible, the client draws the fog.
|
||||
- **#113:** Integration of server fog data into the client fog renderer. The existing `fog_renderer.gd` is a stub. This ticket connects it to actual visibility data from the snapshot. Fog returns when you leave an area (time-based decay, tracked client-side from last-seen tick).
|
||||
- **WorldRenderer:** The existing `world_renderer.gd` orchestrates entity + fog rendering. It already calls `entity_renderer.update_entities()` and `fog_renderer.update_fog()` — the stubs just need real implementations.
|
||||
|
||||
## Parallelism
|
||||
|
||||
```
|
||||
#116 (camera) — independent, start immediately
|
||||
#129 (tiles) — independent, start immediately
|
||||
#130 (sprites) — independent, start immediately
|
||||
#131 (fog overlay) — needs #129 done
|
||||
#113 (fog integration) — needs #131 + server #112
|
||||
```
|
||||
|
||||
#116, #129, #130 can all be worked in parallel from day one.
|
||||
|
||||
## 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): description" --description "body" --base main --head client
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
# Sprint 2: See — Joint Tasks
|
||||
|
||||
**Goal:** Fog of perception working through the bridge — server computes LOS visibility, client renders fog.
|
||||
|
||||
**Branches:** `server` + `client` (merge to main for integration)
|
||||
|
||||
## Pre-Sprint
|
||||
|
||||
| Task | Owner | Notes |
|
||||
|------|-------|-------|
|
||||
| Resolve Q-018 (shadowcast algorithm) | Tyre, Dudley | Blocks #110. Benchmark symmetric vs recursive at 150x150 scale. |
|
||||
| Resolve Q-019 (entity ID stability) | Tyre, Dudley | Affects client entity lifecycle (#130). |
|
||||
| Design ObserverSnapshot v2 schema | Tyre | Add visible_tiles, player_facing, game_time fields. Both teams need this before fog integration. |
|
||||
|
||||
## Integration Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #81 | End-to-end connection test | Sprint 1 carry-over (in_progress) |
|
||||
| NEW | Fog data through bridge | Server #112, Client #113 |
|
||||
| NEW | Sprint 2 proof: fog of perception | All above |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/architecture.md` — D-020 (IPC protocol, ObserverSnapshot), D-010 (information boundaries)
|
||||
- `decisions/perception.md` — D-011 (fog non-negotiable), D-015 (vision cone)
|
||||
|
||||
## Sprint Completion Proof
|
||||
|
||||
**"Walk into a room and see the fog"** — the sprint is done when:
|
||||
|
||||
1. Player character moves on screen (Sprint 1 baseline, maintained)
|
||||
2. Camera follows the player character (no panning)
|
||||
3. Tiles render from snapshot data (floor + walls visible)
|
||||
4. Entities appear/disappear based on line-of-sight
|
||||
5. Fog covers areas outside the vision cone
|
||||
6. Walking behind a wall hides what's on the other side
|
||||
7. Walking around a corner reveals what's there
|
||||
|
||||
This is the first moment the game *feels* like an immersive sim — you can't see behind walls, and that constraint IS the game.
|
||||
|
||||
## Notes
|
||||
|
||||
- **#81 (carry-over):** End-to-end connection test still in_progress from Sprint 1. Must complete before fog integration work.
|
||||
- **ObserverSnapshot v2:** The current `ObserverSnapshot` (`server/src/bridge/types.rs`) only has `tick` + `entities: Vec<VisibleEntity>`. Sprint 2 needs: tile visibility data, facing direction, time-of-day. Design the expanded schema before both teams start, so the contract is clear.
|
||||
- **Fog data through bridge:** Server #112 produces visibility-filtered snapshots. Client #113 consumes them. The bridge already handles MessagePack serialization — new fields just need to be added to both sides.
|
||||
- **Test plan per D-030 Phase 1:** Sprint 2 aligns with D-030's "Phase 1 (sprint 1-2): test infra + collision/pathfinding/time." Collision tests exist (`movement.rs`). Shadowcasting (#110) needs unit tests for known LOS scenarios (corridor, corner peek, wall block). Vision cone (#111) needs sector boundary tests.
|
||||
|
||||
## 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(scope): description" --description "body" --base main --head <branch>
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
# Sprint 2: See — Server Tasks
|
||||
|
||||
**Goal:** Fog of perception working through the bridge — server computes LOS visibility, client renders fog.
|
||||
|
||||
**Branch:** `server`
|
||||
**Agents:** Dudley (simulation), Oscar (networking)
|
||||
|
||||
## Carry-over from Sprint 1
|
||||
|
||||
| # | Title | Status | Notes |
|
||||
|---|-------|--------|-------|
|
||||
| #236 | Tile collision system | ready | WalkabilityMap exists, needs wall data for LOS |
|
||||
|
||||
## New Tickets
|
||||
|
||||
| # | Title | Blocked by |
|
||||
|---|-------|------------|
|
||||
| #110 | Shadowcasting algorithm - server | #236 (walls needed for LOS) |
|
||||
| #111 | Vision cone implementation | #110 |
|
||||
| #112 | Observer visibility query | #111 |
|
||||
| #25 | Game clock and day-phase system | — (SimulationTime exists, needs day-phase integration into snapshot) |
|
||||
|
||||
Use `db/connectors/ticket show <id>` for full details.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- `decisions/perception.md` — D-011 (fog non-negotiable), D-015 (locked camera + vision cone), D-018 (three-range sound model)
|
||||
- `decisions/architecture.md` — D-010 (information boundaries), D-020 (ObserverSnapshot), D-031 (time system)
|
||||
|
||||
## Open Questions to Resolve Early
|
||||
|
||||
- **Q-018: Shadowcasting algorithm selection** — symmetric (Albert Ford) vs recursive. Needs benchmarking at 150x150 scale. Resolve before #110 starts.
|
||||
- **Q-019: Entity ID stability** — how `entity_id: u64` maps to bevy `Entity`. Affects client entity lifecycle.
|
||||
- **Q-021: Tick budget overflow policy** — what happens when a tick exceeds 100ms.
|
||||
|
||||
## Notes
|
||||
|
||||
- **#236 (carry-over):** `WalkabilityMap` and `validate_movement` are already implemented (`server/src/simulation/movement.rs`). The remaining work is integrating wall/blocked tile data that the shadowcasting algorithm needs. Walls must be both collision barriers AND LOS occluders.
|
||||
- **#110:** Core of the sprint. Implement LOS calculation per z-level. The `WalkabilityMap` stores tile walkability in chunks — the shadowcasting system reads this (or a parallel opacity map) to determine what blocks vision. Output: set of visible tiles for a given observer position.
|
||||
- **#111:** Vision cone sectors (forward/peripheral/behind per D-015). Facing direction component needed. Forward = full LOS range, peripheral = reduced range + dimmer, behind = blind. The cone modulates the shadowcast output.
|
||||
- **#112:** Given an observer entity, return visible entities and tiles. This is the system that populates `ObserverSnapshot.entities` with only what the observer can see. Currently the snapshot includes ALL entities (no filtering). This ticket adds the filter.
|
||||
- **#25:** `SimulationTime` already exists (`server/src/simulation/time.rs`) with tick/pause/day-phase. Remaining: include time data in `ObserverSnapshot` so the client can display it. May also need `FacingDirection` component for vision cone.
|
||||
- **ObserverSnapshot expansion:** The `ObserverSnapshot` struct (`server/src/bridge/types.rs`) needs new fields: `visible_tiles: Vec<VisibleTile>` (or bitmap), `player_facing: Direction`, `game_time: TimeData`. Design this before implementation starts.
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
#236 (walls) → #110 (shadowcast) → #111 (vision cone) → #112 (observer query)
|
||||
#25 (time) → standalone, parallel track
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
||||
Reference in New Issue
Block a user