feat(simulation): Sprint 6 Touch — stances, verbs, inventory, anomaly #21

Closed
jpmschweitzer wants to merge 0 commits from server into main
Owner

Summary

Sprint 6 server deliverables: movement stances, tile occupancy, two-phase verb computation, smuggler inventory, and sprint anomaly monologue.

Tickets (9/9 done)

  • #449 ObserverSnapshot v6 — player_stance + player_inventory wire fields
  • #417 Stance system — Sprint/Walk/Careful/Crouch with tick-based movement
  • #420 Same-tile occupancy — TilePresence with posture layers
  • #421 ObjectType component + verb sets per type (Phase 1)
  • #422 Two-phase verb computation — KG-gated Phase 2 observer filter
  • #424 Smuggler inventory — CarriedBy component, Take/Place verbs, info boundary
  • #418 MovementProfile component per archetype
  • #419 Sprint interaction buffer suppression (D-055)
  • #428 Sprint anomaly double-take monologue (D-055)

Key decisions implemented

  • D-053 (stance toggle), D-054 (tile occupancy), D-055 (sprint suppression), D-057 (two-phase verbs), D-065 (smuggler inventory)

Stats

  • 4,406 lines added across 24 files
  • 331 tests (131 new), 0 failures
  • Protocol bumped from v5 to v6

Unblocks

  • Client #438 (inventory UI) and #439 (stance UI) via ObserverSnapshot v6
  • Client #432 (interaction list) via two-phase verb computation

🤖 Generated with Claude Code

## Summary Sprint 6 server deliverables: movement stances, tile occupancy, two-phase verb computation, smuggler inventory, and sprint anomaly monologue. ### Tickets (9/9 done) - **#449** ObserverSnapshot v6 — player_stance + player_inventory wire fields - **#417** Stance system — Sprint/Walk/Careful/Crouch with tick-based movement - **#420** Same-tile occupancy — TilePresence with posture layers - **#421** ObjectType component + verb sets per type (Phase 1) - **#422** Two-phase verb computation — KG-gated Phase 2 observer filter - **#424** Smuggler inventory — CarriedBy component, Take/Place verbs, info boundary - **#418** MovementProfile component per archetype - **#419** Sprint interaction buffer suppression (D-055) - **#428** Sprint anomaly double-take monologue (D-055) ### Key decisions implemented - D-053 (stance toggle), D-054 (tile occupancy), D-055 (sprint suppression), D-057 (two-phase verbs), D-065 (smuggler inventory) ### Stats - 4,406 lines added across 24 files - 331 tests (131 new), 0 failures - Protocol bumped from v5 to v6 ### Unblocks - Client #438 (inventory UI) and #439 (stance UI) via ObserverSnapshot v6 - Client #432 (interaction list) via two-phase verb computation 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 8 commits 2026-02-14 16:01:38 +01:00
Implements the core Sprint 6: Touch systems across 5 tickets:

- #449 ObserverSnapshot v6: add player_stance (MovementStance) and
  player_inventory (Vec<InventoryItem>) wire fields with serde defaults
  for backward compatibility. Bump PROTOCOL_VERSION 5→6.

- #417 Stance system: Sprint/Walk/Careful/Crouch movement stance with
  tick-based speed (1/2/3/4 ticks per move), monologue rate multipliers,
  and PlayerMoveCooldown component. ToggleStanceUp/Down player actions.

- #420 TilePresence: posture-layer collision system allowing same-tile
  occupancy for different layers (Standing/Prone/Seated/Fixture).
  Layer-based collision in validate_movement.

- #421 ObjectType component: Readable/Container/Terminal/Door/Pickup/
  Furniture types with Phase 1 verb sets computed from type + proximity.

- #422 Phase 2 verb filter: KG-gated observer-side verb processing —
  POI priority flips, Confront injection at KnowsDetails+, contradiction
  marking, archetype-specific label relabeling (Smuggler/Detective).

217 unit tests + 17 integration tests passing. All MessagePack fixtures
regenerated for v6 wire format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement physical inventory system per D-065:

- CarriedBy(StableId) component marks items as carried by an entity
- ItemName and InventorySlot components for display and slot assignment
- Take verb: removes TilePosition, adds CarriedBy + InventorySlot
- Place verb: removes CarriedBy + InventorySlot, adds TilePosition
- Observer snapshot populates player_inventory from carried items query
- Info boundary: carried items lack TilePosition, naturally excluded
  from all spatial queries (visibility, interactions) for other entities
- 9-slot capacity (3x3 grid per OQ-24), auto-assigns first free slot
- 8 new tests covering take, place, sequential slots, full rejection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MovementProfile component with per-archetype default stances (D-053).
Sprint stance now explicitly clears the interaction buffer — no verbs
computed or sent during sprint (D-055). Anomaly monologue pipeline is
unaffected (handled by separate system).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When sprinting past a Contradicted entity, queue a delayed retroactive
monologue that fires after ~1.5s: "Wait — something wasn't right back
there." SprintAnomalyQueue component with first-in-wins semantics.
Detection in observer pipeline, processing in monologue system.
Wire MovementProfile, Stance, and SprintAnomalyQueue into player spawn.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive test suites across sprint 6 systems:
- Phase 2 observer filter: Confront injection, archetype label relabeling,
  contradiction marking, POI priority ordering (12 tests)
- Sprint anomaly: detection during sprint, queue semantics, delay timing,
  D-055 visible-but-suppressed integration (7 tests)
- Wire format: Confront and CharacterArchetype msgpack roundtrip (4 tests)
- TilePresence: 4-layer coexistence on same tile (1 test)
- Inventory: Take/Place full roundtrip, capacity enforcement (3 tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Review: server -> main (type: code)

Hoshe (Code Quality): APPROVE

Well-implemented, comprehensively tested PR. 331 tests covering happy paths, edge cases, and integration scenarios. Clean Phase 1/Phase 2 separation properly enforces D-010 information boundary.

# File Severity Issue
1 input.rs:204 warning apply_move() uses .expect() which could panic if world state is corrupted. Consider replacing with early-return let Ok(..) = ... else { return }
2 inventory.rs:63 warning collect_inventory_for() fallback to entity.to_bits() masks bugs. Consider adding debug_assert! in test builds
3 stance.rs:77 suggestion u32::MAX initialization for first-move-immediate is clever but could be clearer with a named constant
4 monologue.rs:52 suggestion ANOMALY_DELAY_TICKS=90 hardcoded; consider making configurable for playtesting
5 observer/mod.rs:158 suggestion archetype_verb_label() will grow; consider extracting to separate module later
6 inventory.rs:28 suggestion find_next_slot() O(n) scan is fine for n=9, document for future
7 interaction.rs:114 suggestion Add trace log when sprint suppresses interactions for debugging

Tyre (Architecture): APPROVE

Architecturally sound implementation with excellent adherence to non-negotiable baselines. All features respect D-010 (info boundary), D-012 (chunk-based world), and maintain clean Phase 1/Phase 2 separation. Performance implications are bounded and within budget.

# File Severity Issue
1 monologue.rs:43 warning No logging when sprint anomaly queue drops subsequent anomalies (first-in-wins). Add trace for debugging
2 types.rs:92 warning 3x3 grid size (9 slots) hardcoded in multiple locations. Consider centralizing the dimension constant
3 stance.rs:72 warning u32::MAX saturation strategy for first-move is clever but potentially confusing. Consider explicit doc or flag
4 observer/mod.rs:131 suggestion Phase 2 filter has multiple in-place mutation passes. Document intended execution order
5 inventory.rs:67 suggestion Soft error on missing EntityRegistry entry is correct per D-020, but add debug assertion for tests
6 interaction.rs suggestion File may exceed 800 lines after +717 additions. Consider submodule split in future refactor

Verdict: APPROVED

Both reviewers approve. No critical issues. All warnings are minor (logging, documentation, defensive assertions) and don't block merge.

🤖 Reviewed with Claude Code

## Review: server -> main (type: code) ### Hoshe (Code Quality): APPROVE Well-implemented, comprehensively tested PR. 331 tests covering happy paths, edge cases, and integration scenarios. Clean Phase 1/Phase 2 separation properly enforces D-010 information boundary. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | `input.rs:204` | warning | `apply_move()` uses `.expect()` which could panic if world state is corrupted. Consider replacing with early-return `let Ok(..) = ... else { return }` | | 2 | `inventory.rs:63` | warning | `collect_inventory_for()` fallback to `entity.to_bits()` masks bugs. Consider adding `debug_assert!` in test builds | | 3 | `stance.rs:77` | suggestion | `u32::MAX` initialization for first-move-immediate is clever but could be clearer with a named constant | | 4 | `monologue.rs:52` | suggestion | `ANOMALY_DELAY_TICKS=90` hardcoded; consider making configurable for playtesting | | 5 | `observer/mod.rs:158` | suggestion | `archetype_verb_label()` will grow; consider extracting to separate module later | | 6 | `inventory.rs:28` | suggestion | `find_next_slot()` O(n) scan is fine for n=9, document for future | | 7 | `interaction.rs:114` | suggestion | Add trace log when sprint suppresses interactions for debugging | ### Tyre (Architecture): APPROVE Architecturally sound implementation with excellent adherence to non-negotiable baselines. All features respect D-010 (info boundary), D-012 (chunk-based world), and maintain clean Phase 1/Phase 2 separation. Performance implications are bounded and within budget. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | `monologue.rs:43` | warning | No logging when sprint anomaly queue drops subsequent anomalies (first-in-wins). Add trace for debugging | | 2 | `types.rs:92` | warning | 3x3 grid size (9 slots) hardcoded in multiple locations. Consider centralizing the dimension constant | | 3 | `stance.rs:72` | warning | `u32::MAX` saturation strategy for first-move is clever but potentially confusing. Consider explicit doc or flag | | 4 | `observer/mod.rs:131` | suggestion | Phase 2 filter has multiple in-place mutation passes. Document intended execution order | | 5 | `inventory.rs:67` | suggestion | Soft error on missing EntityRegistry entry is correct per D-020, but add debug assertion for tests | | 6 | `interaction.rs` | suggestion | File may exceed 800 lines after +717 additions. Consider submodule split in future refactor | ### Verdict: APPROVED Both reviewers approve. No critical issues. All warnings are minor (logging, documentation, defensive assertions) and don't block merge. 🤖 Reviewed with Claude Code
jpmschweitzer closed this pull request 2026-02-14 16:10:20 +01:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jpmschweitzer/settled-reach#21