Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
e2c4623
sprint 023: plan — trigger table on typed event taxonomy, lair death …
vladmesh Jul 12, 2026
7e79701
sprint 023 phase 1: task breakdown
vladmesh Jul 12, 2026
6d491e7
sprint 023 phase 1 task 1: type world event payloads
vladmesh Jul 12, 2026
f687637
sprint 023 phase 1 task 2: type entity lifecycle events
vladmesh Jul 12, 2026
338e8dd
sprint 023 phase 1 task 2.5: split attack events
vladmesh Jul 12, 2026
df5a4c6
sprint 023 phase 1 task 3: type action events
vladmesh Jul 12, 2026
55c802e
sprint 023 phase 1: close — typed event taxonomy, integration 160 gre…
vladmesh Jul 12, 2026
a51d1aa
sprint 023 phase 2: task breakdown
vladmesh Jul 12, 2026
b1b8fe6
sprint 023 phase 2 task 1: add lair death provenance
vladmesh Jul 12, 2026
15d1a9f
test: stabilize wait fast-forward websocket assertion
vladmesh Jul 12, 2026
1dea163
sprint 023 phase 2 task 2: write back lair deaths
vladmesh Jul 12, 2026
b42de03
sprint 023 phase 2 task 3: deliver cascade events
vladmesh Jul 13, 2026
cdb8ba9
sprint 023 phase 2: close — ecology death write-back
vladmesh Jul 13, 2026
4e74210
sprint 023 phase 3: task breakdown
vladmesh Jul 13, 2026
757ea33
sprint 023 phase 3 task 1: add trigger contract index
vladmesh Jul 13, 2026
cfbec06
sprint 023 phase 3 task 2: wire event activation lifecycle
vladmesh Jul 13, 2026
d34139f
sprint 023 phase 3 task 3: persist and complete triggers
vladmesh Jul 13, 2026
41efa48
sprint 023 phase 3: close - trigger lifecycle
vladmesh Jul 13, 2026
b3f57eb
sprint 023 phase 4: task breakdown
vladmesh Jul 13, 2026
3c5c07d
sprint 023 phase 4 task 1: add GM activation controls
vladmesh Jul 13, 2026
838708f
sprint 023 phase 4 task 2: add GM activation panel
vladmesh Jul 13, 2026
c647c0c
sprint 023 phase 4 task 3: contain action input errors
vladmesh Jul 13, 2026
adee60b
sprint 023 phase 4 task 4: fix Dash action contract
vladmesh Jul 13, 2026
aa58956
sprint 023 phase 4: close - GM controls and containment
vladmesh Jul 13, 2026
b6536f9
audit: full codebase - 14 issues found
vladmesh Jul 13, 2026
a4d5dad
sprint 023: audit triaged
vladmesh Jul 13, 2026
0d84106
sprint 023 phase 5: task breakdown
vladmesh Jul 13, 2026
310c336
sprint 023 phase 5 task 1: unify typed event contract
vladmesh Jul 13, 2026
38ec41f
sprint 023 phase 5 task 1: close typed event tests
vladmesh Jul 13, 2026
255808e
sprint 023 phase 5 task 2: split entity event flow
vladmesh Jul 13, 2026
4237517
sprint 023 phase 5 task 2: restore trigger runtime after load
vladmesh Jul 13, 2026
3d0c87e
sprint 023 phase 5 task 3: split transport builders
vladmesh Jul 13, 2026
33a9948
sprint 023 phase 5 task 4: contain protocol errors
vladmesh Jul 13, 2026
65eb963
sprint 023 phase 5: close post-audit refactor
vladmesh Jul 13, 2026
31bcaac
audit: full codebase - 11 issues found
vladmesh Jul 13, 2026
9b1073d
sprint 023: audit triaged
vladmesh Jul 13, 2026
a098e25
sprint 023 phase 6: task breakdown
vladmesh Jul 13, 2026
0527848
sprint 023 phase 6 task 1: localize live combat events
vladmesh Jul 13, 2026
9b05e4e
sprint 023 phase 6 task 2: hide stale master sessions
vladmesh Jul 13, 2026
8ebc4bf
e2e: record sprint 023 post-audit locale blocker
vladmesh Jul 13, 2026
7fc1d01
sprint 023 phase 7: task breakdown
vladmesh Jul 13, 2026
8521a37
sprint 023 phase 7 task 1: localize live action failures
vladmesh Jul 13, 2026
90dab65
sprint 023 phase 7: close locale E2E follow-up
vladmesh Jul 13, 2026
00d68ea
audit: follow up after sprint 023 phase 7
vladmesh Jul 13, 2026
e1b25a8
sprint 023: triage follow-up audit
vladmesh Jul 13, 2026
6b6fc27
docs: record Sprint 023 post-audit E2E blocker
vladmesh Jul 13, 2026
4604cde
sprint 023 phase 8: task breakdown
vladmesh Jul 13, 2026
1225a8a
sprint 023 phase 8 task 1: align Paladin E2E contract
vladmesh Jul 13, 2026
ed79e8f
docs: record Paladin E2E level-up blocker
vladmesh Jul 13, 2026
e6e6ca2
sprint 023 phase 8: plan level-up re-entry repair
vladmesh Jul 13, 2026
76f0640
sprint 023 phase 8 task 3: restore level-up re-entry
vladmesh Jul 13, 2026
8904bac
docs: record Paladin E2E continuation
vladmesh Jul 13, 2026
8a585da
sprint 023 phase 8: record Paladin E2E continuation
vladmesh Jul 13, 2026
f88179f
sprint 023 phase 8: record Paladin E2E continuation
vladmesh Jul 13, 2026
2c7fb83
docs: record partial post-audit E2E
vladmesh Jul 13, 2026
4de9e59
docs: record core post-audit E2E
vladmesh Jul 13, 2026
d0c22c4
docs: record master mutation e2e block
vladmesh Jul 13, 2026
05aba2f
docs: record fighter equipment e2e block
vladmesh Jul 13, 2026
a03b124
sprint 023 phase 8: report Dash and condition E2E
vladmesh Jul 13, 2026
bf7f19c
docs: record final post-audit E2E areas
vladmesh Jul 13, 2026
27f357d
docs: plan lair lifecycle follow-up
vladmesh Jul 13, 2026
c9ee753
docs: add lair lifecycle task card
vladmesh Jul 14, 2026
5dfbf5b
sprint 023 phase 8 task 4: fix lair core lifecycle
vladmesh Jul 14, 2026
fa39715
sprint 023 phase 8: verify lair lifecycle E2E
vladmesh Jul 14, 2026
beed3b3
docs: mark sprint 023 task 2 done
vladmesh Jul 14, 2026
c820d3c
sprint 023 phase 8: close paladin E2E
vladmesh Jul 14, 2026
a625ea7
audit: full codebase — 11 issues found
vladmesh Jul 14, 2026
4824228
sprint 023: triage final audit
vladmesh Jul 14, 2026
29db120
sprint 023: record final post-audit E2E
vladmesh Jul 14, 2026
9b0a189
docs: update living docs (full sync, 7 files)
vladmesh Jul 14, 2026
ad04b9e
sprint 023: close — trigger table and lair write-back
vladmesh Jul 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude/skills/update-docs/state.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"last_run": "2026-07-12",
"last_run": "2026-07-14",
"last_run_mode": "full",
"last_commit": "7575bd3",
"last_full_run": "2026-07-12"
"last_commit": "29db120",
"last_full_run": "2026-07-14"
}
4 changes: 2 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ WebSocket flow (React frontend):

`GameSession` (in `service/session.py`) owns the `Round` lifecycle — starting and stopping the round thread, bridging events to transport listeners via `SessionEventListener` protocol. The `Round` class separates combat and peaceful turns. Combat locations use initiative order (d20 + DEX mod, rolled once at combat start); peaceful creatures use default order. Each creature's turn is a multi-action loop: a `TurnBudget` is created from creature stats, then the brain is called repeatedly until it returns `end_turn` or the budget is exhausted. `ActionDispatcher` (`service/action_dispatcher.py`) is the single entry point: it validates preconditions via `rules/validation.py` (alive, budget, target validity, weapon reach), routes to the appropriate handler in `rules/handlers/`, and consumes budget on success. `ActionProvider` (`rules/action_provider.py`) determines available actions per creature based on state, inventory, and weapon. Brains receive structured awareness (`PeacefulAwareness` or `CombatAwareness` from `core/awareness.py`) with the current budget attached, so they can make informed decisions. Three brain types: `RuleBrain` (utility scoring), `LlmBrain` (LLM calls), `PlayerBrain` (queue + on_turn callback for interactive I/O). `World.advance_time()` checks each layer in order (0 → N) and only ticks those whose `tick_interval` has elapsed since their last tick. This way a 6-second combat round doesn't trigger monthly political updates. Events generated during ticks are propagated to all other layers.

`World.handle_event()` sends an event to all layers in order. Each layer returns an `ActionResult`if any layer returns `success=False`, propagation stops and the failure is returned to the caller. This lets layers validate and reject actions (e.g., EntitiesLayer rejects attacks on dead targets).
`World.handle_event()` sends an event to all layers in order. Each layer returns an `ActionResult`; if any layer returns `success=False`, propagation stops and the failure is returned to the caller. This lets layers validate and reject actions (for example, EntitiesLayer rejects attacks on dead targets).

Events carry an optional `observer_ids` field (`frozenset[str] | None`). When `None`, the event is public — visible to all entities in the area. When set, only listed entity IDs can perceive the event. The `perception` module in `layers/entities/` converts raw events into subjective text through `observer.perceive()`, so the same event reads differently to different characters.
Each `EventType` has a fixed immutable payload class in `core/events.py`; `Event` validates the pairing at construction, and transport/log boundaries encode it to JSON-safe data. Events carry an optional `observer_ids` field (`frozenset[str] | None`). When `None`, the event is public; when set, only listed entity IDs can perceive it. The entities trigger index matches typed payload fields against YAML-defined paired `{on, until}` conditions, changing a creature's activation reason without scanning all creatures. The `perception` module converts visible events into subjective text through `observer.perceive()`.

## Time System

Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ frontend/ — React + TypeScript SPA (Vite, shadcn/ui, Zustand)

### Entity Hierarchy

`Entity` (id, name, location_id, active, on_tick) → `Creature` (physical stats, combat state, `is_anchor`, persisted `current_intent`, brain, turn budget, equipment and resources) → `Character` (race, class, alignment, class features, level and XP) → `PlayerCharacter` / `Npc`. Creature delegates decisions to `brain.choose_action()`. `Container` (`core/container.py`) is a separate `Entity` sibling of `Creature`: inventory + gold, no HP/turn/brain, used for lair treasuries and other lootable world objects (`EntityKind.CONTAINER`). The `perceive()` method controls what an observer sees; LLM prompts never receive raw character data. All tracked entities live on `EntitiesLayer`. `World.location_graph` maps locations to regions/settlements and supplies weighted routes for travel intents. NPCs have structured memory (`NpcMemory`) readable by both LLM and RuleBrain. Combat is managed via `CombatState` and `BattleMap`; grid movement rules live in `rules/movement.py`.
`Entity` (id, name, location_id, active, on_tick) → `Creature` (physical stats, combat state, `is_anchor`, persisted `current_intent`, brain, turn budget, equipment, resources and activation triggers) → `Character` (race, class, alignment, class features, level and XP) → `PlayerCharacter` / `Npc`. Creature delegates decisions to `brain.choose_action()`. `Container` (`core/container.py`) is a separate `Entity` sibling of `Creature`: inventory + gold, no HP/turn/brain, used for lair treasuries and other lootable world objects (`EntityKind.CONTAINER`). The `perceive()` method controls what an observer sees; LLM prompts never receive raw character data. All tracked entities live on `EntitiesLayer`. `World.location_graph` maps locations to regions/settlements and supplies weighted routes for travel intents. NPCs have structured memory (`NpcMemory`) readable by both LLM and RuleBrain. Combat is managed via `CombatState` and `BattleMap`; grid movement rules live in `rules/movement.py`.

### Multi-Action Turns

Expand Down Expand Up @@ -133,7 +133,7 @@ Centralized derived stat computation (`core/modifiers.py` data types, `rules/mod

### Activation & Fast-Forward

Anchor-based activation: `EntitiesLayer.update_activation(time)` runs at the start of each round. Any living creature with `is_anchor=True` and no current intent holds its scene active; creatures at an anchor's location become active, all others go dormant. Creatures in combat stay active regardless. Wait, sleep, and travel are typed, persisted `current_intent` values. When no creature needs a turn, `Round.run_loop()` fast-forwards to the nearest timer or travel-leg boundary. Travel follows deterministic shortest paths one graph edge at a time and can be interrupted by damage, combat, or an occupied scene. Content requires explicit locations. On entering a location with an encounter table, `ActivationManager` rolls encounters (see Lairs, Encounters & Loot).
Anchor-based activation: `EntitiesLayer.update_activation(time)` runs at the start of each round. Any living creature with `is_anchor=True` and no current intent holds its scene active; creatures at an anchor's location become active, all others go dormant. Content may additionally declare paired typed event triggers `{on, until}`: the indexed runtime activates a creature when `on` matches and removes that trigger reason when `until` matches; persistent GM overrides can force active or dormant. Creatures in combat stay active regardless. Wait, sleep, and travel are typed, persisted `current_intent` values. When no creature needs a turn, `Round.run_loop()` fast-forwards to the nearest timer or travel-leg boundary. Travel follows deterministic shortest paths one graph edge at a time and can be interrupted by damage, combat, or an occupied scene. Content requires explicit locations. On entering a location with an encounter table, `ActivationManager` rolls encounters (see Lairs, Encounters & Loot).

### Lairs, Encounters & Loot

Expand Down
Loading
Loading