Sprint 6 client team delivery: movement stances, fog shader rebuild, multi-verb interactions, smuggler inventory, and the three-scope z-layer rendering architecture.
Upgrade client protocol bridge from v5 to v6 to match server.
Adds player_stance (4 variants) and player_inventory decode to
ObserverSnapshot. Adds TOGGLE_STANCE_UP/DOWN to InputMapper.
Includes 25 gdUnit4 tests for v6 decode + server serialization
test gap fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Well-architected Sprint 6 implementation with 1,361 lines of test code across 4 test files. Fog shader rebuild, cursor state machine, and UI components are cleanly separated and follow D-049 z-layer architecture. Three critical bugs must be fixed before merge.
#
File
Severity
Issue
1
fog_state.gd:99-108
critical
_compute_bounds() crashes on all-invalid tile arrays — min/max sentinels produce negative-sized Rect2i, crashing _resize() with negative image dimensions. Add guard: if min_x > max_x: return Rect2i(0,0,1,1)
2
fog_shader.gd:46-50
critical
Hardcoded zoom := Vector2(2.0, 2.0) with "must match Camera2D" comment — hidden coupling breaks silently if zoom ever changes. Read zoom from actual Camera2D node instead.
3
world_radial.gd:150-153
critical
global_position = _origin - size / 2.0 relies on size being initialized, but no explicit size is set on this Control. First open will position incorrectly. Set custom_minimum_size in _ready() based on radial geometry.
4
cursor_renderer.gd:118-125
warning
EntityRenderer._color_for_kind() called as static but not declared static — fragile if EntityRenderer is refactored. Extract to Constants.gd or mark explicitly static.
5
fog.gdshader:27-28
warning
PERIPHERAL_LOW = 0.15 is far below actual peripheral value (0.706). Peripheral tiles will render as "light fog" in a very narrow band — may not match D-059 visual intent. Review thresholds.
6
main.gd:39-44
warning
Monologue consumption has no tick-based deduplication — if snapshot polling has edge cases, same monologue could show twice or be lost.
7
fog_state.gd:79-95
suggestion
_prev_visible.duplicate() is shallow copy — correct for Dictionary<Vector2i, bool> but document the assumption.
8
interaction_list.gd:79,119
suggestion
is_instance_valid(lbl) checks before queue_free() suggest ownership ambiguity — document why or remove if unnecessary.
Coverage gaps: no tests for _compute_bounds() with invalid input, no tests for radial positioning, no fog shader performance test at 1080p.
Tyre (Architecture): APPROVE
Exemplary architectural work. The three-scope z-layer pipeline (D-049) maps 1:1 to the spec. D-010/D-012 baselines fully respected — GameState is pure data store, protocol v6 maintains strict wire format discipline, information boundaries honored (cursor LOS gating, fog knowledge-graph-driven). Coupling is unidirectional: FogShader → FogState → GameState. All 1,361 test lines validate decision compliance. Production-ready.
#
File
Severity
Issue
1
fog_state.gd:66
suggestion
Exploration decay is immediate (255→128) — gradual decay over game-time would better represent fading memory. v0.2+ enhancement.
2
cursor_renderer.gd:90
suggestion
Bracket _hover_offset cached from _detect_hover() — recalculate in _draw() from current canvas transform to avoid wobble during camera movement.
3
interaction_list.gd:19
suggestion
FADE_IN=0.12s / FADE_OUT=0.10s differs from cursor's 150ms — align or document rationale for mismatch.
4
world_radial.gd:119
suggestion
Pause action reused for both game freeze and insert toggle — consider separate ToggleInsert action in protocol v7+.
5
—
suggestion
No .msgpack fixtures for v6 stance/inventory variations — add snapshot_v6_sprint.msgpack etc. for regression protection.
Verdict: CHANGES REQUESTED
Tyre approves architecture. Hoshe flags 3 critical bugs that need fixing before merge: (1) fog_state _compute_bounds crash on edge-case input, (2) fog_shader hardcoded zoom — hidden coupling, (3) world_radial sizing — uninitialized Control size.
## Review: client -> main (type: code)
### Hoshe (Code Quality): REQUEST_CHANGES
Well-architected Sprint 6 implementation with 1,361 lines of test code across 4 test files. Fog shader rebuild, cursor state machine, and UI components are cleanly separated and follow D-049 z-layer architecture. Three critical bugs must be fixed before merge.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | fog_state.gd:99-108 | critical | `_compute_bounds()` crashes on all-invalid tile arrays — min/max sentinels produce negative-sized Rect2i, crashing `_resize()` with negative image dimensions. Add guard: `if min_x > max_x: return Rect2i(0,0,1,1)` |
| 2 | fog_shader.gd:46-50 | critical | Hardcoded `zoom := Vector2(2.0, 2.0)` with "must match Camera2D" comment — hidden coupling breaks silently if zoom ever changes. Read zoom from actual Camera2D node instead. |
| 3 | world_radial.gd:150-153 | critical | `global_position = _origin - size / 2.0` relies on `size` being initialized, but no explicit size is set on this Control. First open will position incorrectly. Set `custom_minimum_size` in `_ready()` based on radial geometry. |
| 4 | cursor_renderer.gd:118-125 | warning | `EntityRenderer._color_for_kind()` called as static but not declared static — fragile if EntityRenderer is refactored. Extract to Constants.gd or mark explicitly static. |
| 5 | fog.gdshader:27-28 | warning | `PERIPHERAL_LOW = 0.15` is far below actual peripheral value (0.706). Peripheral tiles will render as "light fog" in a very narrow band — may not match D-059 visual intent. Review thresholds. |
| 6 | main.gd:39-44 | warning | Monologue consumption has no tick-based deduplication — if snapshot polling has edge cases, same monologue could show twice or be lost. |
| 7 | fog_state.gd:79-95 | suggestion | `_prev_visible.duplicate()` is shallow copy — correct for Dictionary<Vector2i, bool> but document the assumption. |
| 8 | interaction_list.gd:79,119 | suggestion | `is_instance_valid(lbl)` checks before `queue_free()` suggest ownership ambiguity — document why or remove if unnecessary. |
Coverage gaps: no tests for `_compute_bounds()` with invalid input, no tests for radial positioning, no fog shader performance test at 1080p.
### Tyre (Architecture): APPROVE
Exemplary architectural work. The three-scope z-layer pipeline (D-049) maps 1:1 to the spec. D-010/D-012 baselines fully respected — GameState is pure data store, protocol v6 maintains strict wire format discipline, information boundaries honored (cursor LOS gating, fog knowledge-graph-driven). Coupling is unidirectional: FogShader → FogState → GameState. All 1,361 test lines validate decision compliance. Production-ready.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | fog_state.gd:66 | suggestion | Exploration decay is immediate (255→128) — gradual decay over game-time would better represent fading memory. v0.2+ enhancement. |
| 2 | cursor_renderer.gd:90 | suggestion | Bracket `_hover_offset` cached from `_detect_hover()` — recalculate in `_draw()` from current canvas transform to avoid wobble during camera movement. |
| 3 | interaction_list.gd:19 | suggestion | FADE_IN=0.12s / FADE_OUT=0.10s differs from cursor's 150ms — align or document rationale for mismatch. |
| 4 | world_radial.gd:119 | suggestion | Pause action reused for both game freeze and insert toggle — consider separate `ToggleInsert` action in protocol v7+. |
| 5 | — | suggestion | No `.msgpack` fixtures for v6 stance/inventory variations — add `snapshot_v6_sprint.msgpack` etc. for regression protection. |
### Verdict: CHANGES REQUESTED
Tyre approves architecture. Hoshe flags 3 critical bugs that need fixing before merge: (1) fog_state `_compute_bounds` crash on edge-case input, (2) fog_shader hardcoded zoom — hidden coupling, (3) world_radial sizing — uninitialized Control size.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Sprint 6 client team delivery: movement stances, fog shader rebuild, multi-verb interactions, smuggler inventory, and the three-scope z-layer rendering architecture.
Protocol
Architecture
UI Systems (6 tickets)
Breaking Changes
Test plan
godot --headless --quit— client launches without errors🤖 Generated with Claude Code
Review: client -> main (type: code)
Hoshe (Code Quality): REQUEST_CHANGES
Well-architected Sprint 6 implementation with 1,361 lines of test code across 4 test files. Fog shader rebuild, cursor state machine, and UI components are cleanly separated and follow D-049 z-layer architecture. Three critical bugs must be fixed before merge.
_compute_bounds()crashes on all-invalid tile arrays — min/max sentinels produce negative-sized Rect2i, crashing_resize()with negative image dimensions. Add guard:if min_x > max_x: return Rect2i(0,0,1,1)zoom := Vector2(2.0, 2.0)with "must match Camera2D" comment — hidden coupling breaks silently if zoom ever changes. Read zoom from actual Camera2D node instead.global_position = _origin - size / 2.0relies onsizebeing initialized, but no explicit size is set on this Control. First open will position incorrectly. Setcustom_minimum_sizein_ready()based on radial geometry.EntityRenderer._color_for_kind()called as static but not declared static — fragile if EntityRenderer is refactored. Extract to Constants.gd or mark explicitly static.PERIPHERAL_LOW = 0.15is far below actual peripheral value (0.706). Peripheral tiles will render as "light fog" in a very narrow band — may not match D-059 visual intent. Review thresholds._prev_visible.duplicate()is shallow copy — correct for Dictionary<Vector2i, bool> but document the assumption.is_instance_valid(lbl)checks beforequeue_free()suggest ownership ambiguity — document why or remove if unnecessary.Coverage gaps: no tests for
_compute_bounds()with invalid input, no tests for radial positioning, no fog shader performance test at 1080p.Tyre (Architecture): APPROVE
Exemplary architectural work. The three-scope z-layer pipeline (D-049) maps 1:1 to the spec. D-010/D-012 baselines fully respected — GameState is pure data store, protocol v6 maintains strict wire format discipline, information boundaries honored (cursor LOS gating, fog knowledge-graph-driven). Coupling is unidirectional: FogShader → FogState → GameState. All 1,361 test lines validate decision compliance. Production-ready.
_hover_offsetcached from_detect_hover()— recalculate in_draw()from current canvas transform to avoid wobble during camera movement.ToggleInsertaction in protocol v7+..msgpackfixtures for v6 stance/inventory variations — addsnapshot_v6_sprint.msgpacketc. for regression protection.Verdict: CHANGES REQUESTED
Tyre approves architecture. Hoshe flags 3 critical bugs that need fixing before merge: (1) fog_state
_compute_boundscrash on edge-case input, (2) fog_shader hardcoded zoom — hidden coupling, (3) world_radial sizing — uninitialized Control size.Re-review: client -> main (round 2)
Fix commit
9e8ccb1addresses all issues from round 1.Hoshe (Code Quality): APPROVE
All 3 critical bugs fixed, both warnings addressed, all suggestions documented.
_compute_boundscrashget_viewport().get_camera_2d()with fallbackcustom_minimum_sizein_ready()Constants.color_for_entity_kind()Tyre (Architecture): APPROVE
All 5 suggestions handled. Constants extraction improves Phase 2 (#361) path. No new coupling.
TODO(v0.2)TODO(v7)Verdict: APPROVED — merging.
Pull request closed