feat(server): sprint 3 — tick rate, interactions, content skeleton #16

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

Summary

  • #385 Content directory skeleton — 72 files following D-057 district-as-atomic-pack layout (Sova Transit first district with 17 NPCs, 3 locations, 5 triangles, dialogue/monologue pools, factions, enums)
  • #386 Content schema definitions — 8 JSON Schema files (draft 2020-12) for district, location, npc-profile, dialogue-pool, monologue-pool, triangle, routine, fact-catalog
  • #406 Tick rate scaling (D-052) — TickRate enum (Full/Half/Paused) with fractional accumulation replacing binary pause flag, SetTickRate player action
  • #404 Proximity detection + interaction verbs (D-060) — compute_nearby_interactions system with Manhattan distance ranges, context-sensitive verb computation, ObserverSnapshot v4

Test plan

  • 162 tests passing (143 unit + 19 integration), zero clippy warnings
  • Verify tick rate: Full advances every frame, Half every 2 frames, Paused blocks
  • Verify interaction ranges: close (≤2) gets Talk+Observe, mid (≤5) gets Observe only
  • Verify PersonOfInterest flips verb priority (Observe > Talk)
  • Verify content schemas are valid JSON Schema draft 2020-12
  • Verify backward compat: old v3 snapshots deserialize with serde defaults

🤖 Generated with Claude Code

## Summary - **#385** Content directory skeleton — 72 files following D-057 district-as-atomic-pack layout (Sova Transit first district with 17 NPCs, 3 locations, 5 triangles, dialogue/monologue pools, factions, enums) - **#386** Content schema definitions — 8 JSON Schema files (draft 2020-12) for district, location, npc-profile, dialogue-pool, monologue-pool, triangle, routine, fact-catalog - **#406** Tick rate scaling (D-052) — TickRate enum (Full/Half/Paused) with fractional accumulation replacing binary pause flag, SetTickRate player action - **#404** Proximity detection + interaction verbs (D-060) — compute_nearby_interactions system with Manhattan distance ranges, context-sensitive verb computation, ObserverSnapshot v4 ## Test plan - [ ] 162 tests passing (143 unit + 19 integration), zero clippy warnings - [ ] Verify tick rate: Full advances every frame, Half every 2 frames, Paused blocks - [ ] Verify interaction ranges: close (≤2) gets Talk+Observe, mid (≤5) gets Observe only - [ ] Verify PersonOfInterest flips verb priority (Observe > Talk) - [ ] Verify content schemas are valid JSON Schema draft 2020-12 - [ ] Verify backward compat: old v3 snapshots deserialize with serde defaults 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 8 commits 2026-02-12 19:52:25 +01:00
Pushes current branch and creates or updates a PR without ever
merging into main. Prevents accidental PR merges by restricting
the skill to branch-side operations only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scaffolds the full content directory structure per D-057 spec:
district-as-atomic-pack layout with Sova Transit as the first
district. Includes 17 NPC stubs, 3 locations, 5 triangles,
9 dialogue pools, 8 monologue pools, routines, 7 factions,
7 knowledge catalogs, 8 enum definitions, and global region.
Implements ticket #385.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JSON Schema (draft 2020-12) for content validation: district,
location, npc-profile, dialogue-pool, monologue-pool, triangle,
routine, and fact-catalog. NPC schema uses if/then conditional
for FRIEND pattern validation. Implements ticket #386.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace binary paused flag with TickRate enum (Full/Half/Paused)
per D-052. Full rate advances every frame, Half every 2 frames
via fractional accumulation, Paused blocks all advances. Add
SetTickRate player action for client-driven rate changes.
Implements ticket #406.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement compute_nearby_interactions system that detects entities
within close (≤2) and mid (≤5) Manhattan distance, computes
available verbs per D-060 spec. NPCs get Talk+Observe at close
range, Observe-only at mid range; PersonOfInterest flips priority.
Objects get Examine. Results populate nearby_interactions[] on
ObserverSnapshot v4. Bump protocol version 3→4. Implements #404.

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): REQUEST_CHANGES

The PR implements tick rate scaling, proximity interactions, and content schemas with generally solid code quality. However, there are critical issues around system ordering, wire format consistency, and error handling that must be fixed before merge.

# File Severity Issue
1 observer.rs / interaction.rs critical NearbyInteractionBuffer.interactions is pub and cleared at start of compute_nearby_interactions -- if system ordering is violated, snapshot gets stale/empty data. Make field private with accessor.
2 input.rs:88-89 critical apply_move logs warning if player entity missing but continues. Missing player is a fatal invariant -- should panic, not warn silently.
3 types.rs:29-30 critical #[serde(default)] on nearby_interactions hides serialization bugs. If v4 snapshot is missing the field, client gets empty data without error. Remove the default.
4 observer.rs:172-175 critical Remembered entities use stable_id.0 as fallback entity_id, but visible entities use Entity::to_bits(). ID spaces can collide. Wire entity_id should always be StableId.
5 bridge/mod.rs critical No explicit .after() between compute_nearby_interactions and send_bridge_snapshot in BridgePlugin schedule.
6 interaction.rs:73 warning verbs.sort_by_key with no secondary key -- equal priorities produce undefined ordering.
7 interaction.rs constants warning CLOSE_RANGE and MID_RANGE are pub -- should be pub(crate) or config resource.
8 types.rs:108 warning NearbyInteraction.distance is f32 but manhattan_distance() returns u32. Type mismatch.
9 observer.rs:143-145 warning Remembered entity filter chain is fragile -- 6 sequential if/continue checks. Extract to helper.
10 observer.rs:165 warning No debug assertion that last_observed_tick <= current tick.
11 knowledge/events.rs:33 warning Unregistered target entities silently skipped. Should be error! or debug_assert!.
12 types.rs:75 warning Entity::to_bits() is bevy-version-dependent. Add roundtrip test.
13 observer.rs:172-175 warning Showing remembered entity for despawned entity is a client footgun.
14 time.rs (missing test) warning No test for floating point drift over 10,000+ frames at Half rate.
15 interaction.rs (missing test) warning No test for POI NPC at mid-range, equidistant NPCs, or 50+ entities.
16 serialization.rs:90 warning Fixture deserialize test doesn't assert version == 4.
17 observer.rs suggestion 320 lines, one 150-line function. Split into helpers.
18 types.rs suggestion Will grow rapidly. Split at 200 lines.
19 _schema/ suggestion No validation tooling. Add make validate-content.
20 observer.rs:202 suggestion interaction_buffer.interactions.clone() every frame. Use .take() or Arc.

Tyre (Architecture): REQUEST_CHANGES

The code quality is high, but the architecture is making promises it can't keep. D-010 (multiplayer-ready) and D-017 (perception modes) will break the current design. The interaction system is exemplary. But observer.rs is a growing monolith, snapshot versioning is fragile, and per-entity state is hiding in global Resources.

# File Severity Issue
1 types.rs ObserverSnapshot critical Snapshot versioning via version: u8 + #[serde(default)] is a time bomb. No per-version deserialization, no protocol negotiation. Violates D-020. Need version-tagged enum.
2 observer.rs compute_observer_snapshot critical Function does 6 things. D-017 perception modes will explode this. Split into single-responsibility functions.
3 interaction.rs NearbyInteractionBuffer critical Global Resource for per-observer data. Breaks with 2+ players (D-009). Replace with per-entity Component.
4 _schema/ cross-file validation critical No cross-file constraints. Routine refs npc:kael but nothing validates kael.yaml exists. Need Rust ContentValidator.
5 interaction.rs:3,50-51 warning Interaction system directly queries KnowledgeGraph. Simulation reading perception = boundary violation.
6 observer.rs (entire file) warning Missing PerceptionQuery trait abstraction. Hardcoded for natural vision. D-017 will force duplication.
7 interaction.rs tests warning No LOS occlusion tests. System claims sightline check but doesn't query FOV.
8 types.rs GameTime suggestion paused and tick_rate are redundant. Remove one.
9 time.rs:47-66 suggestion Fractional accumulation undocumented. Add explanation.
10 content directory suggestion District name in path, filename, AND YAML content. Pick one source of truth.

Verdict: CHANGES REQUESTED

Both reviewers agree: solid implementation quality, architectural boundaries need work.

Must fix (blocking):

  • Snapshot versioning strategy (version-tagged enum, not flat struct + serde defaults)
  • Split compute_observer_snapshot into composable pipeline steps
  • Replace NearbyInteractionBuffer Resource with per-entity Component (multiplayer-ready)
  • Wire-format entity_id consistency (always StableId, never Entity::to_bits)
  • System ordering guarantees between interaction computation and snapshot send
  • Content cross-file validation

Should fix:

  • Decouple interaction system from knowledge graph direct queries
  • Remove redundant paused / tick_rate in GameTime
  • Interaction system LOS integration (or remove LOS claims from spec comments)
## Review: server -> main (type: code) ### Hoshe (Code Quality): REQUEST_CHANGES The PR implements tick rate scaling, proximity interactions, and content schemas with generally solid code quality. However, there are critical issues around system ordering, wire format consistency, and error handling that must be fixed before merge. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | observer.rs / interaction.rs | critical | `NearbyInteractionBuffer.interactions` is pub and cleared at start of `compute_nearby_interactions` -- if system ordering is violated, snapshot gets stale/empty data. Make field private with accessor. | | 2 | input.rs:88-89 | critical | `apply_move` logs warning if player entity missing but continues. Missing player is a fatal invariant -- should panic, not warn silently. | | 3 | types.rs:29-30 | critical | `#[serde(default)]` on `nearby_interactions` hides serialization bugs. If v4 snapshot is missing the field, client gets empty data without error. Remove the default. | | 4 | observer.rs:172-175 | critical | Remembered entities use `stable_id.0` as fallback entity_id, but visible entities use `Entity::to_bits()`. ID spaces can collide. Wire entity_id should always be StableId. | | 5 | bridge/mod.rs | critical | No explicit `.after()` between `compute_nearby_interactions` and `send_bridge_snapshot` in BridgePlugin schedule. | | 6 | interaction.rs:73 | warning | `verbs.sort_by_key` with no secondary key -- equal priorities produce undefined ordering. | | 7 | interaction.rs constants | warning | `CLOSE_RANGE` and `MID_RANGE` are `pub` -- should be `pub(crate)` or config resource. | | 8 | types.rs:108 | warning | `NearbyInteraction.distance` is `f32` but `manhattan_distance()` returns `u32`. Type mismatch. | | 9 | observer.rs:143-145 | warning | Remembered entity filter chain is fragile -- 6 sequential if/continue checks. Extract to helper. | | 10 | observer.rs:165 | warning | No debug assertion that `last_observed_tick <= current tick`. | | 11 | knowledge/events.rs:33 | warning | Unregistered target entities silently skipped. Should be `error!` or `debug_assert!`. | | 12 | types.rs:75 | warning | `Entity::to_bits()` is bevy-version-dependent. Add roundtrip test. | | 13 | observer.rs:172-175 | warning | Showing remembered entity for despawned entity is a client footgun. | | 14 | time.rs (missing test) | warning | No test for floating point drift over 10,000+ frames at Half rate. | | 15 | interaction.rs (missing test) | warning | No test for POI NPC at mid-range, equidistant NPCs, or 50+ entities. | | 16 | serialization.rs:90 | warning | Fixture deserialize test doesn't assert version == 4. | | 17 | observer.rs | suggestion | 320 lines, one 150-line function. Split into helpers. | | 18 | types.rs | suggestion | Will grow rapidly. Split at 200 lines. | | 19 | _schema/ | suggestion | No validation tooling. Add `make validate-content`. | | 20 | observer.rs:202 | suggestion | `interaction_buffer.interactions.clone()` every frame. Use `.take()` or `Arc`. | ### Tyre (Architecture): REQUEST_CHANGES The code quality is high, but the architecture is making promises it can't keep. D-010 (multiplayer-ready) and D-017 (perception modes) will break the current design. The interaction system is exemplary. But observer.rs is a growing monolith, snapshot versioning is fragile, and per-entity state is hiding in global Resources. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | types.rs ObserverSnapshot | critical | Snapshot versioning via `version: u8` + `#[serde(default)]` is a time bomb. No per-version deserialization, no protocol negotiation. Violates D-020. Need version-tagged enum. | | 2 | observer.rs compute_observer_snapshot | critical | Function does 6 things. D-017 perception modes will explode this. Split into single-responsibility functions. | | 3 | interaction.rs NearbyInteractionBuffer | critical | Global `Resource` for per-observer data. Breaks with 2+ players (D-009). Replace with per-entity `Component`. | | 4 | _schema/ cross-file validation | critical | No cross-file constraints. Routine refs npc:kael but nothing validates kael.yaml exists. Need Rust `ContentValidator`. | | 5 | interaction.rs:3,50-51 | warning | Interaction system directly queries KnowledgeGraph. Simulation reading perception = boundary violation. | | 6 | observer.rs (entire file) | warning | Missing `PerceptionQuery` trait abstraction. Hardcoded for natural vision. D-017 will force duplication. | | 7 | interaction.rs tests | warning | No LOS occlusion tests. System claims sightline check but doesn't query FOV. | | 8 | types.rs GameTime | suggestion | `paused` and `tick_rate` are redundant. Remove one. | | 9 | time.rs:47-66 | suggestion | Fractional accumulation undocumented. Add explanation. | | 10 | content directory | suggestion | District name in path, filename, AND YAML content. Pick one source of truth. | ### Verdict: CHANGES REQUESTED **Both reviewers agree: solid implementation quality, architectural boundaries need work.** **Must fix (blocking):** - Snapshot versioning strategy (version-tagged enum, not flat struct + serde defaults) - Split `compute_observer_snapshot` into composable pipeline steps - Replace `NearbyInteractionBuffer` Resource with per-entity Component (multiplayer-ready) - Wire-format entity_id consistency (always StableId, never Entity::to_bits) - System ordering guarantees between interaction computation and snapshot send - Content cross-file validation **Should fix:** - Decouple interaction system from knowledge graph direct queries - Remove redundant `paused` / `tick_rate` in GameTime - Interaction system LOS integration (or remove LOS claims from spec comments)
jpmschweitzer added 3 commits 2026-02-12 20:15:01 +01:00
Hoshe + Tyre review items:
- Use StableId consistently for wire entity_id (H4) across observer,
  observation, interpretation, and interaction systems
- Make NearbyInteractionBuffer.interactions private with take() (H1/H20)
- Add system ordering constraint for compute_nearby_interactions (H5)
- Panic on missing PlayerCharacter in input processing (H2)
- Remove redundant paused field from GameTime (Tyre8)
- Remove #[serde(default)] from nearby_interactions (H3)
- Change NearbyInteraction.distance from f32 to u32 (H8)
- Add sort stability for equal verb priorities (H6)
- Scope constants to pub(crate) (H7)
- Add debug_assert for last_observed_tick ordering (H10)
- Strengthen unregistered entity handling to debug_assert + error (H11)
- Document fractional tick accumulation (Tyre9)
- Extract collect_remembered_entities helper (Tyre2/H17)
- Add half_rate_no_drift_over_10000_frames test (H14)
- Add mid-range and deterministic sort tests (H15)
- Add fixture version assertion (H16)
- Regenerate msgpack fixtures for wire format changes

146 unit + 19 integration tests pass, zero clippy warnings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-added system/station/district fields to district.yaml that were
incorrectly removed during Tyre10 cleanup. These carry hierarchical
context (planet, station), not redundant identity. Made canonical_id
optional in schema since it's derived from directory path at load time.

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

Supplementary Review: Content Directory Scalability (Tyre, Architecture)

Verdict: REQUEST_CHANGES

The current content/districts/{slug}/ flat structure works for v0.1 but has critical structural weaknesses at galaxy scale (300 planets, 1000s of districts). Changing this after 100+ districts exist is 10x the cost. Fix now.


Failure Scenarios at Scale

# Problem Scale Threshold Severity
1 Flat 1000-directory explosioncontent/districts/ with 1000 sibling dirs x 35 files = 35,000+ files. Git status 10-30s, editor indexing thrashes, CI checkout doubles. ~200 districts critical
2 ID-to-path mismatch — Canonical IDs are {system}.{station}.{district} but paths are flat districts/{slug}/. "All districts in Krenn system" requires parsing 1000 YAMLs instead of ls systems/krenn/. ~50 districts critical
3 NPC slug collisionsnpc:{slug} is a global namespace but NPCs live in district-scoped dirs. Two districts with npcs/dock-worker.yaml = ID collision. No enforcement exists. ~50 districts critical
4 content.yaml manifest bloat — 1000 districts = 3000+ lines. Every branch that adds a district touches this file = constant merge conflicts. ~100 districts high
5 Procedural gen undefined — D-023 Tier 2/3 content is templated/procedural. Where do generated districts live? YAML on disk = file explosion. In-memory only = dual content systems. Sprint 5+ critical
6 Cross-district references unspecified — D-025 says NPCs can hold roles in multiple social sites. If NPC in District A relates to NPC in District B, where does that live? No ownership model defined. ~20 districts high
7 Git perf degrades catastrophically — 35,000 small YAML files. Branch touching 50 districts (1750 files) takes minutes to rebase. ~200 districts critical
8 D-003 multi-campaign incompatible — No campaign namespace in directory structure. Adding "Foundation Saga" campaign = mixed with Commonwealth content. Campaign #2 medium

Recommended Fix: Hierarchical Directory Structure

Before (current):

content/districts/sova-transit/district.yaml

After (proposed):

content/campaigns/commonwealth/systems/krenn/stations/sova/districts/transit/district.yaml

Path derivation: campaigns/{campaign}/systems/{system}/stations/{station}/districts/{district}/

  • Filesystem matches canonical IDs — directory walk replaces YAML parsing for spatial queries
  • Git performance: 10-20 stations/system, 5-10 districts/station — no flat explosion
  • Multi-campaign ready (D-003)
  • Content loader scans via glob systems/**/districts/ — no per-district manifest entry

Required: NPC ID Namespace Strategy

Recommended: district-scoped slugsnpc:sova-transit.dock-worker. File stays npcs/dock-worker.yaml, loader prepends district context. Cross-district refs use full ID. Within-district refs use short form.

Schema change: "^npc:[a-z][a-z0-9-]+(\\.[a-z][a-z0-9-]+)?$"

Required: Replace content.yaml with Discovery Convention

version: "0.1.0"
campaigns:
  - id: "commonwealth"
    path: "campaigns/commonwealth"
    discovery: "systems/**/districts/"

Loader scans for district.yaml under glob. No per-district listing = no merge conflicts, no manifest bloat.

Required: Content Validation CLI

Even simple: walk tree, validate JSONSchema, check cross-references (no dangling npc:*), detect slug collisions. Expand to full build tool later.

Can Wait (Sprint 5+)

  • Git LFS for content (not needed until 100MB+)
  • Content submodules (wait for 5+ parallel writers)
  • Binary content format (wait for loading perf concerns)
  • Procedural content storage strategy (flag now, implement later)

Cost Estimate

  • Directory restructure + NPC ID scoping: ~2-3 dev-days
  • Content validation CLI: ~1 dev-day
  • Total: ~4 dev-days, before Sprint 3 content authoring starts

After 50 districts: 10x the cost (merge conflicts, author retraining, tool updates).

## Supplementary Review: Content Directory Scalability (Tyre, Architecture) ### Verdict: REQUEST_CHANGES The current `content/districts/{slug}/` flat structure works for v0.1 but has **critical structural weaknesses at galaxy scale** (300 planets, 1000s of districts). Changing this after 100+ districts exist is 10x the cost. Fix now. --- ### Failure Scenarios at Scale | # | Problem | Scale Threshold | Severity | |---|---------|----------------|----------| | 1 | **Flat 1000-directory explosion** — `content/districts/` with 1000 sibling dirs x 35 files = 35,000+ files. Git status 10-30s, editor indexing thrashes, CI checkout doubles. | ~200 districts | critical | | 2 | **ID-to-path mismatch** — Canonical IDs are `{system}.{station}.{district}` but paths are flat `districts/{slug}/`. "All districts in Krenn system" requires parsing 1000 YAMLs instead of `ls systems/krenn/`. | ~50 districts | critical | | 3 | **NPC slug collisions** — `npc:{slug}` is a global namespace but NPCs live in district-scoped dirs. Two districts with `npcs/dock-worker.yaml` = ID collision. No enforcement exists. | ~50 districts | critical | | 4 | **content.yaml manifest bloat** — 1000 districts = 3000+ lines. Every branch that adds a district touches this file = constant merge conflicts. | ~100 districts | high | | 5 | **Procedural gen undefined** — D-023 Tier 2/3 content is templated/procedural. Where do generated districts live? YAML on disk = file explosion. In-memory only = dual content systems. | Sprint 5+ | critical | | 6 | **Cross-district references unspecified** — D-025 says NPCs can hold roles in multiple social sites. If NPC in District A relates to NPC in District B, where does that live? No ownership model defined. | ~20 districts | high | | 7 | **Git perf degrades catastrophically** — 35,000 small YAML files. Branch touching 50 districts (1750 files) takes minutes to rebase. | ~200 districts | critical | | 8 | **D-003 multi-campaign incompatible** — No campaign namespace in directory structure. Adding "Foundation Saga" campaign = mixed with Commonwealth content. | Campaign #2 | medium | --- ### Recommended Fix: Hierarchical Directory Structure **Before (current):** ``` content/districts/sova-transit/district.yaml ``` **After (proposed):** ``` content/campaigns/commonwealth/systems/krenn/stations/sova/districts/transit/district.yaml ``` Path derivation: `campaigns/{campaign}/systems/{system}/stations/{station}/districts/{district}/` - Filesystem matches canonical IDs — directory walk replaces YAML parsing for spatial queries - Git performance: 10-20 stations/system, 5-10 districts/station — no flat explosion - Multi-campaign ready (D-003) - Content loader scans via glob `systems/**/districts/` — no per-district manifest entry ### Required: NPC ID Namespace Strategy Recommended: **district-scoped slugs** — `npc:sova-transit.dock-worker`. File stays `npcs/dock-worker.yaml`, loader prepends district context. Cross-district refs use full ID. Within-district refs use short form. Schema change: `"^npc:[a-z][a-z0-9-]+(\\.[a-z][a-z0-9-]+)?$"` ### Required: Replace content.yaml with Discovery Convention ```yaml version: "0.1.0" campaigns: - id: "commonwealth" path: "campaigns/commonwealth" discovery: "systems/**/districts/" ``` Loader scans for `district.yaml` under glob. No per-district listing = no merge conflicts, no manifest bloat. ### Required: Content Validation CLI Even simple: walk tree, validate JSONSchema, check cross-references (no dangling `npc:*`), detect slug collisions. Expand to full build tool later. ### Can Wait (Sprint 5+) - Git LFS for content (not needed until 100MB+) - Content submodules (wait for 5+ parallel writers) - Binary content format (wait for loading perf concerns) - Procedural content storage strategy (flag now, implement later) --- ### Cost Estimate - Directory restructure + NPC ID scoping: ~2-3 dev-days - Content validation CLI: ~1 dev-day - **Total: ~4 dev-days, before Sprint 3 content authoring starts** After 50 districts: 10x the cost (merge conflicts, author retraining, tool updates).
jpmschweitzer added 4 commits 2026-02-12 22:18:50 +01:00
Replace flat content/districts/ with hierarchical campaign/system/
station/district structure. Path mirrors canonical IDs, enables
glob-based discovery, and is multi-campaign/DLC ready.

- git mv 46 files preserving history
- New metadata: campaign.yaml, system.yaml, station.yaml
- Rewrite content.yaml with glob-based district discovery
- Add campaign, system, station JSON schemas
- Update district schema: hierarchy fields derived from path
- Update npc-profile schema: accept district-scoped IDs
- Add TODO to 17 dialogue/monologue pool files for generator revision
- Update _meta/README.md with new hierarchy documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete generate_snapshot from bridge/mod.rs — superseded by
perception::observer::compute_observer_snapshot. Not referenced
in any schedule or test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace silent Entity::to_bits() fallbacks with tracing::error in
  observer.rs and interaction.rs (makes unregistered entities loud)
- Add PROTOCOL_VERSION constant to types.rs, use in observer snapshot
- Document single-observer assumption on NearbyInteractionBuffer
- Document proximity-only (no LOS) limitation on compute_nearby_interactions

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

Re-Review Round 2: server -> main. See full review below.

Re-Review Round 2: server -> main. See full review below.
Author
Owner

Re-Review: server -> main (type: code) — Round 2

PR #16: feat(server): sprint 3 — tick rate, interactions, content skeleton
7 fix commits since initial review.


Hoshe (Code Quality): REQUEST_CHANGES

Summary: 16/20 known issues fixed correctly. Critical improvements: private interaction buffer with take(), panic on missing player, pub(crate) visibility, u32 distance type, deterministic verb sorting, drift test, debug assertions.

Previous Issues Status:

# Issue Status
1 NearbyInteractionBuffer.interactions pub FIXED — private with take()
2 apply_move warns on missing player FIXED — panics with .expect() + test
3 #[serde(default)] on nearby_interactions FIXED — removed
4 Wire entity_id mixes Entity::to_bits/StableId PARTIALLY FIXED — prefers StableId, error-logged fallback
5 No .after() for send_bridge_snapshot FIXED
6 verbs.sort_by_key no secondary key FIXED(priority, kind as u8)
7 CLOSE_RANGE/MID_RANGE pub FIXEDpub(crate)
8 distance f32 vs u32 FIXED
9 Remembered entity filter chain FIXED — extracted helper
10 No debug_assert for last_observed_tick FIXED
11 Unregistered target entities silently skipped FIXEDerror! + debug_assert!
12 Entity::to_bits() bevy-version-dependent NOT FIXED — no roundtrip test
13 Redundant paused/tick_rate FIXED — removed paused
14 Float drift test FIXED — 10,000 frame test added
15 Missing POI mid-range test FIXED — test added but doesn't assert priority value
16 Fixture version assertion FIXED — asserts version == 4
17 observer.rs file size WORSE — now 798 lines (was ~320)
19 Content validation tooling NOT FIXED — no make validate-content
20 interaction_buffer.clone() FIXED — uses take()

Remaining Issues:

# File Severity Issue
1 server/tests/serialization.rs critical No Entity::to_bits() roundtrip test. Bevy version upgrade could silently break wire IDs.
2 Makefile warning No make validate-content target. JSON Schema files exist but nothing validates content.
3 observer.rs warning 798 lines — 2.5x the previous concern. Extract remembered_entities.rs or move tests to separate file.
4 interaction.rs test suggestion poi_npc_at_mid_range_gets_observe_only should also assert priority value.

Tyre (Architecture): REQUEST_CHANGES

Summary: ~70% of feedback addressed. Content restructure is excellent — hierarchical directory matches canonical IDs, glob discovery eliminates manifest bloat. Three critical architectural time bombs remain: snapshot versioning is cosmetic (no enforcement), observer.rs is still a monolith, NearbyInteractionBuffer is still a global Resource.

Previous Issues Status:

# Issue Status
Tyre #1 Snapshot versioning time bomb OPEN — PROTOCOL_VERSION constant added but zero enforcement. No client rejection.
Tyre #2 compute_observer_snapshot monolith PARTIALLY — Extracted helper. Main function still 120+ lines doing 5 things.
Tyre #3 NearbyInteractionBuffer global Resource OPEN — Still Resource. Documented as single-observer v0.1 assumption.
Tyre #4 Content cross-file validation OPEN — No validator or CLI.
Tyre #5 Interaction queries KnowledgeGraph directly OPEN — boundary violation unchanged.
Tyre #8 Redundant paused/tick_rate RESOLVED
Tyre #10 District name redundancy RESOLVED — derived from path.
Scalability #1 Flat directory explosion RESOLVED — hierarchical structure.
Scalability #2 ID-to-path mismatch RESOLVED — filesystem matches canonical IDs.
Scalability #3 NPC slug collisions OPEN — no namespace scoping.
Scalability #4 content.yaml manifest bloat RESOLVED — glob discovery.

New Architectural Concerns:

# File Severity Issue
N1 types.rs / observer.rs critical PROTOCOL_VERSION is cosmetic — client doesn't check it. Violates D-020.
N2 observer.rs, interaction.rs warning Error logging without recovery — execution continues with garbage fallback wire ID.
N3 time.rs warning No test for TickRate switch mid-accumulation (Half->Full with 0.5 remainder).
N4 content/_schema/ medium NPC ID namespace punted. ContentValidator mentioned but doesn't exist.

Tyre's Recommendation — Path C (partial fix, 2-3 dev-days):

Priority Fix Cost Rationale
Must Snapshot versioning enforcement 1-2 days Every protocol change is a potential silent client break.
Must NearbyInteractionBuffer -> per-entity Component 1 day Multiplayer-ready (D-009).
Defer Observer monolith -> pipeline decomposition Sprint 4 Ugly but not dangerous.
Defer Content cross-file validation CLI Sprint 4 Acceptable at 1-2 authors.
Defer NPC ID namespace scoping Sprint 4 Must happen before 10 districts.

Verdict: CHANGES REQUESTED (Round 2)

What's improved: Content restructure (excellent), code quality fixes (16/20 verified), test coverage, system ordering, dead code removal.

What's still blocking:

  1. Entity::to_bits() roundtrip test (Hoshe) — 30 min fix
  2. Snapshot versioning must be enforced, not cosmetic (Tyre) — 1-2 dev-days
  3. NearbyInteractionBuffer global Resource (Tyre) — 1 dev-day
  4. make validate-content target (Hoshe) — 1 dev-day

Project lead decision needed: Accept Tyre's Path C (fix #2 + #3, defer observer monolith) or Path B (document all as v0.1 debt with tickets)?

## Re-Review: server -> main (type: code) — Round 2 PR #16: feat(server): sprint 3 — tick rate, interactions, content skeleton 7 fix commits since initial review. --- ### Hoshe (Code Quality): REQUEST_CHANGES **Summary:** 16/20 known issues fixed correctly. Critical improvements: private interaction buffer with `take()`, panic on missing player, `pub(crate)` visibility, u32 distance type, deterministic verb sorting, drift test, debug assertions. **Previous Issues Status:** | # | Issue | Status | |---|-------|--------| | 1 | NearbyInteractionBuffer.interactions pub | **FIXED** — private with `take()` | | 2 | apply_move warns on missing player | **FIXED** — panics with `.expect()` + test | | 3 | `#[serde(default)]` on nearby_interactions | **FIXED** — removed | | 4 | Wire entity_id mixes Entity::to_bits/StableId | **PARTIALLY FIXED** — prefers StableId, error-logged fallback | | 5 | No .after() for send_bridge_snapshot | **FIXED** | | 6 | verbs.sort_by_key no secondary key | **FIXED** — `(priority, kind as u8)` | | 7 | CLOSE_RANGE/MID_RANGE pub | **FIXED** — `pub(crate)` | | 8 | distance f32 vs u32 | **FIXED** | | 9 | Remembered entity filter chain | **FIXED** — extracted helper | | 10 | No debug_assert for last_observed_tick | **FIXED** | | 11 | Unregistered target entities silently skipped | **FIXED** — `error!` + `debug_assert!` | | 12 | Entity::to_bits() bevy-version-dependent | **NOT FIXED** — no roundtrip test | | 13 | Redundant paused/tick_rate | **FIXED** — removed `paused` | | 14 | Float drift test | **FIXED** — 10,000 frame test added | | 15 | Missing POI mid-range test | **FIXED** — test added but doesn't assert priority value | | 16 | Fixture version assertion | **FIXED** — asserts `version == 4` | | 17 | observer.rs file size | **WORSE** — now 798 lines (was ~320) | | 19 | Content validation tooling | **NOT FIXED** — no `make validate-content` | | 20 | interaction_buffer.clone() | **FIXED** — uses `take()` | **Remaining Issues:** | # | File | Severity | Issue | |---|------|----------|-------| | 1 | server/tests/serialization.rs | critical | No `Entity::to_bits()` roundtrip test. Bevy version upgrade could silently break wire IDs. | | 2 | Makefile | warning | No `make validate-content` target. JSON Schema files exist but nothing validates content. | | 3 | observer.rs | warning | 798 lines — 2.5x the previous concern. Extract `remembered_entities.rs` or move tests to separate file. | | 4 | interaction.rs test | suggestion | `poi_npc_at_mid_range_gets_observe_only` should also assert priority value. | --- ### Tyre (Architecture): REQUEST_CHANGES **Summary:** ~70% of feedback addressed. **Content restructure is excellent** — hierarchical directory matches canonical IDs, glob discovery eliminates manifest bloat. **Three critical architectural time bombs remain:** snapshot versioning is cosmetic (no enforcement), observer.rs is still a monolith, NearbyInteractionBuffer is still a global Resource. **Previous Issues Status:** | # | Issue | Status | |---|-------|--------| | Tyre #1 | Snapshot versioning time bomb | **OPEN** — PROTOCOL_VERSION constant added but zero enforcement. No client rejection. | | Tyre #2 | compute_observer_snapshot monolith | **PARTIALLY** — Extracted helper. Main function still 120+ lines doing 5 things. | | Tyre #3 | NearbyInteractionBuffer global Resource | **OPEN** — Still Resource. Documented as single-observer v0.1 assumption. | | Tyre #4 | Content cross-file validation | **OPEN** — No validator or CLI. | | Tyre #5 | Interaction queries KnowledgeGraph directly | **OPEN** — boundary violation unchanged. | | Tyre #8 | Redundant paused/tick_rate | **RESOLVED** | | Tyre #10 | District name redundancy | **RESOLVED** — derived from path. | | Scalability #1 | Flat directory explosion | **RESOLVED** — hierarchical structure. | | Scalability #2 | ID-to-path mismatch | **RESOLVED** — filesystem matches canonical IDs. | | Scalability #3 | NPC slug collisions | **OPEN** — no namespace scoping. | | Scalability #4 | content.yaml manifest bloat | **RESOLVED** — glob discovery. | **New Architectural Concerns:** | # | File | Severity | Issue | |---|------|----------|-------| | N1 | types.rs / observer.rs | critical | PROTOCOL_VERSION is cosmetic — client doesn't check it. Violates D-020. | | N2 | observer.rs, interaction.rs | warning | Error logging without recovery — execution continues with garbage fallback wire ID. | | N3 | time.rs | warning | No test for TickRate switch mid-accumulation (Half->Full with 0.5 remainder). | | N4 | content/_schema/ | medium | NPC ID namespace punted. ContentValidator mentioned but doesn't exist. | **Tyre's Recommendation — Path C (partial fix, 2-3 dev-days):** | Priority | Fix | Cost | Rationale | |----------|-----|------|-----------| | **Must** | Snapshot versioning enforcement | 1-2 days | Every protocol change is a potential silent client break. | | **Must** | NearbyInteractionBuffer -> per-entity Component | 1 day | Multiplayer-ready (D-009). | | **Defer** | Observer monolith -> pipeline decomposition | Sprint 4 | Ugly but not dangerous. | | **Defer** | Content cross-file validation CLI | Sprint 4 | Acceptable at 1-2 authors. | | **Defer** | NPC ID namespace scoping | Sprint 4 | Must happen before 10 districts. | --- ### Verdict: CHANGES REQUESTED (Round 2) **What's improved:** Content restructure (excellent), code quality fixes (16/20 verified), test coverage, system ordering, dead code removal. **What's still blocking:** 1. Entity::to_bits() roundtrip test (Hoshe) — 30 min fix 2. Snapshot versioning must be enforced, not cosmetic (Tyre) — 1-2 dev-days 3. NearbyInteractionBuffer global Resource (Tyre) — 1 dev-day 4. `make validate-content` target (Hoshe) — 1 dev-day **Project lead decision needed:** Accept Tyre's Path C (fix #2 + #3, defer observer monolith) or Path B (document all as v0.1 debt with tickets)?
jpmschweitzer added 5 commits 2026-02-12 22:53:28 +01:00
Per-entity Component attached to PlayerCharacter instead of global
Resource. Makes the interaction buffer multiplayer-ready (D-009) —
each observer gets their own buffer without pipeline refactoring.

Updated all 8 files touching the buffer: system signatures, player
spawn bundles, and ~30 test spawn sites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split observer/mod.rs (820 lines) into production code (244 lines) and
tests (480 lines). Reduces module size per Hoshe #3 review item.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Entity::to_bits() roundtrip test guards against bevy version changes
  silently breaking wire IDs (Hoshe #1)
- PROTOCOL_VERSION constant used in test helpers instead of hardcoded 4
- TickRate switch mid-accumulation test verifies Half→Full→Paused→Half
  transitions preserve accumulator state correctly (Tyre N3)
- POI mid-range test now asserts priority=1 (Hoshe #4)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Python script validates campaign YAML files against JSON schemas in
content/_schema/. Maps files to schemas by directory context (npcs/
→ npc-profile.schema.json, etc.). Skips comment-only placeholder stubs.

Addresses Hoshe #2 review item.

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

Re-Review Round 3: server -> main (type: code)

5 new commits since Round 2. Evaluating full punch list.


Hoshe (Code Quality): REQUEST_CHANGES

Summary: 5/12 fully fixed, 3 partially fixed, 4 unfixed. Strong execution on tactical fixes (roundtrip test, Buffer refactor, validation tooling, TickRate tests). Observer pipeline decomposition and PerceptionQuery trait still missing.

Punch List Scorecard:

# Item Status Evidence
1 Entity::to_bits() roundtrip test FIXED serialization.rs:86-99 — covers despawn/respawn generation
2 Snapshot versioning enforcement FIXED (docs) PROTOCOL_VERSION constant + inline strategy docs
3 NearbyInteractionBuffer -> Component FIXED interaction.rs:103-113 — per-entity, multiplayer-ready
4 make validate-content FIXED tooling/validate-content + Makefile target
5 Observer pipeline decomposition NOT FIXED Still 130-line monolith, only tests extracted
6 Content cross-file validation PARTIALLY Per-file schema OK, no cross-reference checking
7 NPC ID namespace scoping FIXED Schema accepts npc:district.slug format
8 PerceptionQuery trait NOT FIXED No trait. Hardcoded for natural vision
9 TickRate switch test FIXED Half->Full->Paused->Half with accumulator carry-over
10 Error-logging-without-recovery PARTIALLY debug_assert + error! pattern — loud but still continues
11 POI priority assertion NOT FIXED Tests check verb kind, not priority field values
12 observer.rs file size PARTIALLY Tests extracted (574 LOC), mod.rs still 244 LOC

Remaining Issues:

# File Severity Issue
1 observer/mod.rs critical Pipeline decomposition not done. 130-line function mixing 7 responsibilities. D-017 modes will force duplication.
2 (none) critical No PerceptionQuery trait abstraction for D-017 mode switching
3 interaction.rs:166-189 suggestion poi_npc_observe_takes_priority doesn't assert priority field values (1 vs 2)

Tyre (Architecture): REQUEST_CHANGES

Summary: ~60% addressed. NearbyInteractionBuffer refactor, content validation, NPC namespace, error handling, TickRate tests all solid. Three critical architectural issues remain: snapshot versioning has no enforcement, observer is still a monolith, and interaction system violates architecture boundaries by reading KnowledgeGraph in simulation phase.

Punch List Scorecard:

# Item Status Assessment
1 Snapshot versioning enforcement PARTIALLY PROTOCOL_VERSION constant exists but client doesn't check it. No rejection mechanism.
2 Observer monolith decomposition NOT FIXED compute_observer_snapshot still 130 lines doing 7 steps. Only tests extracted.
3 NearbyInteractionBuffer -> Component FIXED Per-entity Component. Multiplayer-ready. Solid.
4 Content validation CLI FIXED validate-content script with schema mapping. make target exists.
5 Interaction/Knowledge boundary STILL VIOLATED compute_nearby_interactions reads KnowledgeGraph — simulation reading perception state
6 PerceptionQuery trait NOT FIXED No trait. Hardcoded for natural vision.
7 NPC ID namespace FIXED npc:district.slug pattern in schema.
8 PROTOCOL_VERSION cosmetic PARTIALLY Constant with docs but zero enforcement. Client doesn't check.
9 Error logging without recovery FIXED debug_assert + tracing::error — loud in dev, survives in prod.
10 TickRate switch test FIXED Comprehensive test covering all transitions.

Critical Blockers:

# Issue Impact
1 Snapshot versioning cosmetic Silent data corruption on protocol drift. Client MUST validate version.
2 Observer monolith D-017 perception modes will force 130-line function duplication per mode.
3 Interaction/KnowledgeGraph boundary Simulation phase reading perception output = cycle dependency. Breaks deterministic replay (D-010) and multiplayer desync (D-009).

New concern from Tyre: The interaction system's KnowledgeGraph dependency creates a cross-phase data flow violation. Relationship lookup should move to compute_observer_snapshot (which already reads KG), not live in simulation-phase code.


Verdict: CHANGES REQUESTED (Round 3)

What's fixed and solid:

  • NearbyInteractionBuffer -> Component (multiplayer-ready)
  • Entity::to_bits() roundtrip test
  • make validate-content + schema validation script
  • NPC ID namespace scoping
  • TickRate switch mid-accumulation test
  • Error handling improvements

Still blocking (both reviewers agree):

  1. Observer pipeline decomposition — extract stages from compute_observer_snapshot (~4 hours)
  2. Client-side PROTOCOL_VERSION check + rejection (~1 hour)
  3. Move relationship lookup from interaction system to observer (boundary fix, ~2 hours)

Hoshe also flags: PerceptionQuery trait (not blocking per Tyre — can defer to Sprint 4 pre-D-017)

Estimated remaining work: ~7-8 hours focused effort for the 3 blockers.

## Re-Review Round 3: server -> main (type: code) 5 new commits since Round 2. Evaluating full punch list. --- ### Hoshe (Code Quality): REQUEST_CHANGES **Summary:** 5/12 fully fixed, 3 partially fixed, 4 unfixed. Strong execution on tactical fixes (roundtrip test, Buffer refactor, validation tooling, TickRate tests). Observer pipeline decomposition and PerceptionQuery trait still missing. **Punch List Scorecard:** | # | Item | Status | Evidence | |---|------|--------|----------| | 1 | Entity::to_bits() roundtrip test | **FIXED** | serialization.rs:86-99 — covers despawn/respawn generation | | 2 | Snapshot versioning enforcement | **FIXED** (docs) | PROTOCOL_VERSION constant + inline strategy docs | | 3 | NearbyInteractionBuffer -> Component | **FIXED** | interaction.rs:103-113 — per-entity, multiplayer-ready | | 4 | make validate-content | **FIXED** | tooling/validate-content + Makefile target | | 5 | Observer pipeline decomposition | **NOT FIXED** | Still 130-line monolith, only tests extracted | | 6 | Content cross-file validation | **PARTIALLY** | Per-file schema OK, no cross-reference checking | | 7 | NPC ID namespace scoping | **FIXED** | Schema accepts npc:district.slug format | | 8 | PerceptionQuery trait | **NOT FIXED** | No trait. Hardcoded for natural vision | | 9 | TickRate switch test | **FIXED** | Half->Full->Paused->Half with accumulator carry-over | | 10 | Error-logging-without-recovery | **PARTIALLY** | debug_assert + error! pattern — loud but still continues | | 11 | POI priority assertion | **NOT FIXED** | Tests check verb kind, not priority field values | | 12 | observer.rs file size | **PARTIALLY** | Tests extracted (574 LOC), mod.rs still 244 LOC | **Remaining Issues:** | # | File | Severity | Issue | |---|------|----------|-------| | 1 | observer/mod.rs | critical | Pipeline decomposition not done. 130-line function mixing 7 responsibilities. D-017 modes will force duplication. | | 2 | (none) | critical | No PerceptionQuery trait abstraction for D-017 mode switching | | 3 | interaction.rs:166-189 | suggestion | poi_npc_observe_takes_priority doesn't assert priority field values (1 vs 2) | --- ### Tyre (Architecture): REQUEST_CHANGES **Summary:** ~60% addressed. NearbyInteractionBuffer refactor, content validation, NPC namespace, error handling, TickRate tests all solid. Three critical architectural issues remain: snapshot versioning has no enforcement, observer is still a monolith, and interaction system violates architecture boundaries by reading KnowledgeGraph in simulation phase. **Punch List Scorecard:** | # | Item | Status | Assessment | |---|------|--------|------------| | 1 | Snapshot versioning enforcement | **PARTIALLY** | PROTOCOL_VERSION constant exists but client doesn't check it. No rejection mechanism. | | 2 | Observer monolith decomposition | **NOT FIXED** | compute_observer_snapshot still 130 lines doing 7 steps. Only tests extracted. | | 3 | NearbyInteractionBuffer -> Component | **FIXED** | Per-entity Component. Multiplayer-ready. Solid. | | 4 | Content validation CLI | **FIXED** | validate-content script with schema mapping. make target exists. | | 5 | Interaction/Knowledge boundary | **STILL VIOLATED** | compute_nearby_interactions reads KnowledgeGraph — simulation reading perception state | | 6 | PerceptionQuery trait | **NOT FIXED** | No trait. Hardcoded for natural vision. | | 7 | NPC ID namespace | **FIXED** | npc:district.slug pattern in schema. | | 8 | PROTOCOL_VERSION cosmetic | **PARTIALLY** | Constant with docs but zero enforcement. Client doesn't check. | | 9 | Error logging without recovery | **FIXED** | debug_assert + tracing::error — loud in dev, survives in prod. | | 10 | TickRate switch test | **FIXED** | Comprehensive test covering all transitions. | **Critical Blockers:** | # | Issue | Impact | |---|-------|--------| | 1 | Snapshot versioning cosmetic | Silent data corruption on protocol drift. Client MUST validate version. | | 2 | Observer monolith | D-017 perception modes will force 130-line function duplication per mode. | | 3 | Interaction/KnowledgeGraph boundary | Simulation phase reading perception output = cycle dependency. Breaks deterministic replay (D-010) and multiplayer desync (D-009). | **New concern from Tyre:** The interaction system's `KnowledgeGraph` dependency creates a cross-phase data flow violation. Relationship lookup should move to `compute_observer_snapshot` (which already reads KG), not live in simulation-phase code. --- ### Verdict: CHANGES REQUESTED (Round 3) **What's fixed and solid:** - NearbyInteractionBuffer -> Component (multiplayer-ready) - Entity::to_bits() roundtrip test - make validate-content + schema validation script - NPC ID namespace scoping - TickRate switch mid-accumulation test - Error handling improvements **Still blocking (both reviewers agree):** 1. Observer pipeline decomposition — extract stages from compute_observer_snapshot (~4 hours) 2. Client-side PROTOCOL_VERSION check + rejection (~1 hour) 3. Move relationship lookup from interaction system to observer (boundary fix, ~2 hours) **Hoshe also flags:** PerceptionQuery trait (not blocking per Tyre — can defer to Sprint 4 pre-D-017) **Estimated remaining work:** ~7-8 hours focused effort for the 3 blockers.
jpmschweitzer added 3 commits 2026-02-12 23:33:17 +01:00
Extract visibility geometry into a separate system behind a
PerceptionQuery trait, enabling D-017 perception mode swapping.
Two-stage pipeline: compute_visibility_geometry writes to
VisibilityGeometry resource, compute_observer_snapshot reads it.

Remove KnowledgeGraph from compute_nearby_interactions (simulation
phase boundary violation). Verb availability stays in simulation;
POI-based priority adjustment moves to observer via
apply_poi_verb_priority helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client now rejects snapshots where version != PROTOCOL_VERSION (4).
Returns null with error log on mismatch. Test snapshot updated to
use Protocol.PROTOCOL_VERSION and v4 game_time format (tick_rate
replaces paused field).

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

Re-Review Round 4: server -> main (type: code)

2 new commits addressing final 3 blockers.


Hoshe (Code Quality): APPROVE

Summary: All 3 Round 3 blockers fixed correctly. Observer pipeline genuinely decomposed into two-stage system. Client enforces PROTOCOL_VERSION with fail-fast rejection. Interaction system no longer reads KnowledgeGraph. Bonus: PerceptionQuery trait abstraction and POI priority test with kind+value assertions.

# Blocker Status Evidence
1 Observer pipeline decomposition FIXED Two-stage: compute_visibility_geometry -> compute_observer_snapshot. Helper functions extracted.
2 Client PROTOCOL_VERSION check FIXED protocol.gd rejects version != 4 with push_error + return null.
3 Interaction/KG boundary fix FIXED KnowledgeGraph removed from interaction query. POI priority moved to observer.
4 PerceptionQuery trait (bonus) FIXED query.rs: trait + NaturalVision impl + ActivePerceptionMode resource.
5 POI priority assertion (bonus) FIXED Tests assert both verb kind AND priority values.
6 Observer file size (bonus) ACCEPTABLE mod.rs 273 LOC + query.rs 103 LOC. Tests in separate 617 LOC file.

No new issues found. No regressions detected.


Tyre (Architecture): APPROVE

Summary: All three blockers architecturally resolved, not just cosmetically patched. PerceptionQuery trait is well-designed for D-017 mode swapping. Phase boundary between simulation and perception is now correct per D-010. System ordering is explicit and correct. Foundation is multiplayer-ready, perception-mode-ready, and testable.

# Blocker Status Architectural Assessment
1 Snapshot versioning FIXED Client enforces version check before field access. Fail-fast. D-020 compliant.
2 Observer decomposition FIXED Two-stage pipeline via VisibilityGeometry resource. PerceptionQuery trait enables D-017 mode swapping without touching entity filtering.
3 Interaction/KG boundary FIXED Simulation determines verb availability by proximity only. Observer applies POI priority from knowledge graph. Phase boundary correct per D-010.

D-017 readiness: Thermal vision implements PerceptionQuery with different geometry, observer pipeline unchanged.
D-009 readiness: Per-entity Component buffer, per-observer geometry. Multi-observer ready.
D-030 readiness: Simulation no longer reads perception state. Deterministic replay unbroken.

No new architectural concerns.


Verdict: APPROVED

Both reviewers approve. All blockers from Rounds 1-4 resolved. PR ready for merge.

Final tally across 4 review rounds:

  • Round 1: 44 issues identified (5 critical Hoshe, 4 critical Tyre)
  • Round 2: ~70% fixed, 3 blockers remained
  • Round 3: ~60% of remaining fixed, 3 final blockers
  • Round 4: All blockers resolved. Clean approval.

Architecture highlights:

  • PerceptionQuery trait for D-017 perception mode extensibility
  • Two-stage observer pipeline (geometry -> snapshot)
  • Clean simulation/perception phase boundary
  • Per-entity interaction buffer (D-009 multiplayer-ready)
  • Client-enforced protocol versioning
  • Hierarchical content directory with glob discovery
  • Content validation tooling
## Re-Review Round 4: server -> main (type: code) 2 new commits addressing final 3 blockers. --- ### Hoshe (Code Quality): APPROVE **Summary:** All 3 Round 3 blockers fixed correctly. Observer pipeline genuinely decomposed into two-stage system. Client enforces PROTOCOL_VERSION with fail-fast rejection. Interaction system no longer reads KnowledgeGraph. Bonus: PerceptionQuery trait abstraction and POI priority test with kind+value assertions. | # | Blocker | Status | Evidence | |---|---------|--------|----------| | 1 | Observer pipeline decomposition | **FIXED** | Two-stage: `compute_visibility_geometry` -> `compute_observer_snapshot`. Helper functions extracted. | | 2 | Client PROTOCOL_VERSION check | **FIXED** | protocol.gd rejects version != 4 with push_error + return null. | | 3 | Interaction/KG boundary fix | **FIXED** | KnowledgeGraph removed from interaction query. POI priority moved to observer. | | 4 | PerceptionQuery trait (bonus) | **FIXED** | query.rs: trait + NaturalVision impl + ActivePerceptionMode resource. | | 5 | POI priority assertion (bonus) | **FIXED** | Tests assert both verb kind AND priority values. | | 6 | Observer file size (bonus) | **ACCEPTABLE** | mod.rs 273 LOC + query.rs 103 LOC. Tests in separate 617 LOC file. | No new issues found. No regressions detected. --- ### Tyre (Architecture): APPROVE **Summary:** All three blockers architecturally resolved, not just cosmetically patched. PerceptionQuery trait is well-designed for D-017 mode swapping. Phase boundary between simulation and perception is now correct per D-010. System ordering is explicit and correct. Foundation is multiplayer-ready, perception-mode-ready, and testable. | # | Blocker | Status | Architectural Assessment | |---|---------|--------|-------------------------| | 1 | Snapshot versioning | **FIXED** | Client enforces version check before field access. Fail-fast. D-020 compliant. | | 2 | Observer decomposition | **FIXED** | Two-stage pipeline via VisibilityGeometry resource. PerceptionQuery trait enables D-017 mode swapping without touching entity filtering. | | 3 | Interaction/KG boundary | **FIXED** | Simulation determines verb availability by proximity only. Observer applies POI priority from knowledge graph. Phase boundary correct per D-010. | **D-017 readiness:** Thermal vision implements PerceptionQuery with different geometry, observer pipeline unchanged. **D-009 readiness:** Per-entity Component buffer, per-observer geometry. Multi-observer ready. **D-030 readiness:** Simulation no longer reads perception state. Deterministic replay unbroken. No new architectural concerns. --- ### Verdict: APPROVED Both reviewers approve. All blockers from Rounds 1-4 resolved. PR ready for merge. **Final tally across 4 review rounds:** - Round 1: 44 issues identified (5 critical Hoshe, 4 critical Tyre) - Round 2: ~70% fixed, 3 blockers remained - Round 3: ~60% of remaining fixed, 3 final blockers - Round 4: All blockers resolved. Clean approval. **Architecture highlights:** - PerceptionQuery trait for D-017 perception mode extensibility - Two-stage observer pipeline (geometry -> snapshot) - Clean simulation/perception phase boundary - Per-entity interaction buffer (D-009 multiplayer-ready) - Client-enforced protocol versioning - Hierarchical content directory with glob discovery - Content validation tooling
jpmschweitzer closed this pull request 2026-02-12 23:40:18 +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#16