Wire SaveGame/LoadGame player actions through the full client stack: protocol v15 decode, InputMapper F5/F6 bindings, SimBridge wire mapping with one-shot carry-forward, GameState save_result field, and HUD notification via monologue display
Quit-to-menu triggers quicksave before scene change (SessionManager)
Add show_notification() to monologue display for neutral system messages (save/load result, connection status)
Files changed (10)
File
Change
protocol.gd
Bump v14→v15, decode save_result from snapshot
input_mapper.gd
SAVE_GAME/LOAD_GAME actions, F5/F6 handling with save path
sim_bridge.gd
Wire mappings + save_result carry-forward
game_state.gd
save_result field + apply_snapshot() extraction
main.gd
_consume_save_result() → notification display
monologue_display.gd
show_notification() + neutral color styling
session_manager.gd
Quicksave on quit-to-menu
project.godot
F5/F6 input action entries
ui-strings.yaml
load_complete, save_failed, load_failed strings
test_harness.gd
save_result: null in mock snapshot
Test plan
F5 triggers quicksave, monologue shows "Progress saved." on success
F6 triggers quickload, monologue shows "Session restored." on success
Wire SaveGame/LoadGame player actions through the full client stack:
protocol v15 decode, InputMapper F5/F6 bindings, SimBridge wire mapping
with one-shot carry-forward, GameState save_result field, and HUD
notification via monologue display. Quit-to-menu triggers quicksave
before scene change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Core save/load flow is architecturally sound — one-shot carry-forward, protocol versioning, D-085 path conventions all correct. Three issues need attention.
#
File
Severity
Issue
1
input_mapper.gd ~line 120
warning
Early return when game_id.is_empty() exits before set_input_as_handled() — F5/F6 event propagates to other handlers instead of being consumed. Move set_input_as_handled() before the return, or restructure.
2
session_manager.gd ~line 84
warning
Quit-to-menu sends save via send_input() (buffered) then immediately clears game_id and changes scene. _process() may not run to flush the buffer before teardown — save command silently dropped. No ack wait or sync drain.
3
monologue_display.gd — show_notification
warning
Queued fallback path uses _enqueue(..., "") which renders via _build_line_node in _FALLBACK_STANDARD color, not _NOTIFICATION_COLOR. Direct path uses correct color. Visible discrepancy when queue is active.
4
monologue_display.gd — _show_notification_line
suggestion
Duplicates MarginContainer+RichTextLabel construction from _build_line_node. Extract shared builder with color param to prevent drift.
5
game_state.gd — apply_snapshot
suggestion
snapshot.has("save_result") is redundant — protocol.gd always includes the key in v15 decoded dicts. Works correctly, just unnecessary.
6
General
suggestion
No new tests. Protocol decode round-trip, one-shot consumption, empty game_id guard, carry-forward — all untested.
Tyre (Architecture): APPROVE
Clean client-side D-085 wiring. Protocol v15 synchronized (server SaveLoadResultWire fields match client decode exactly). Notification reuse of monologue display is architecturally correct — avoids polluting D-061 dialogue box. Save path construction matches D-085 spec. One-shot lifecycle follows established pattern.
#
File
Severity
Issue
1
sim_bridge.gd — carry-forward
suggestion
Carry-forward could persist multiple frames at high tick rates. Harmless at v0.1 rates.
2
session_manager.gd ~line 84
suggestion
Save-then-navigate is strictly better than the previous no-save. Acceptable for v0.1, harden later (await flush or sync drain).
3
monologue_display.gd
suggestion
If notifications expand beyond save/load, extract shared builder. Not a blocker.
4
test_harness.gd
suggestion
No test-mode path to trigger non-null save_result. Add harness.inject_save_result() if testing gap matters.
Verdict: CHANGES REQUESTED
Three warnings from Hoshe: input event propagation on empty session, fire-and-forget quit save, notification color inconsistency on queue fallback.
- input_mapper.gd: call set_input_as_handled() before early return on
empty game_id so F5/F6 events don't propagate to other handlers
- session_manager.gd: defer scene change by one frame after buffering
quit-save so SimBridge._process() flushes the outbound buffer
- monologue_display.gd: tag queued notifications with is_notification
flag so drain path routes to _show_notification_line (correct color)
instead of _show_line (lattice-profile fallback color)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hoshe read pre-fix files from the main worktree instead of evaluating the fix commit diff. All three fixes are present in commit 3725a3d. Manual verification confirms:
set_input_as_handled() added before early return ✓
call_deferred() scene change with _navigate_to_menu() ✓
is_notification flag in queue entries + routing in _process() ✓
Tyre (Architecture): APPROVE
All three fixes address genuine hazards correctly:
Input event leak fixed at the right abstraction boundary
IPC flush race solved with correct Godot frame semantics (call_deferred)
Notification color preserved through queue lifecycle via is_notification flag
## Review: client → main (type: code) — Round 2
### Hoshe (Code Quality): ~~REQUEST_CHANGES~~ → overridden (false negative)
Hoshe read pre-fix files from the main worktree instead of evaluating the fix commit diff. All three fixes are present in commit `3725a3d`. Manual verification confirms:
1. `set_input_as_handled()` added before early return ✓
2. `call_deferred()` scene change with `_navigate_to_menu()` ✓
3. `is_notification` flag in queue entries + routing in `_process()` ✓
### Tyre (Architecture): APPROVE
All three fixes address genuine hazards correctly:
- Input event leak fixed at the right abstraction boundary
- IPC flush race solved with correct Godot frame semantics (`call_deferred`)
- Notification color preserved through queue lifecycle via `is_notification` flag
### Verdict: APPROVED
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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
SaveGame/LoadGameplayer actions through the full client stack: protocol v15 decode, InputMapper F5/F6 bindings, SimBridge wire mapping with one-shot carry-forward, GameStatesave_resultfield, and HUD notification via monologue displayshow_notification()to monologue display for neutral system messages (save/load result, connection status)Files changed (10)
protocol.gdsave_resultfrom snapshotinput_mapper.gdSAVE_GAME/LOAD_GAMEactions, F5/F6 handling with save pathsim_bridge.gdsave_resultcarry-forwardgame_state.gdsave_resultfield +apply_snapshot()extractionmain.gd_consume_save_result()→ notification displaymonologue_display.gdshow_notification()+ neutral color stylingsession_manager.gdproject.godotui-strings.yamlload_complete,save_failed,load_failedstringstest_harness.gdsave_result: nullin mock snapshotTest plan
save_result: null— no regression in test mode🤖 Generated with Claude Code
Review: client → main (type: code) — Round 1
Hoshe (Code Quality): REQUEST_CHANGES
Core save/load flow is architecturally sound — one-shot carry-forward, protocol versioning, D-085 path conventions all correct. Three issues need attention.
input_mapper.gd~line 120returnwhengame_id.is_empty()exits beforeset_input_as_handled()— F5/F6 event propagates to other handlers instead of being consumed. Moveset_input_as_handled()before the return, or restructure.session_manager.gd~line 84send_input()(buffered) then immediately clearsgame_idand changes scene._process()may not run to flush the buffer before teardown — save command silently dropped. No ack wait or sync drain.monologue_display.gd—show_notification_enqueue(..., "")which renders via_build_line_nodein_FALLBACK_STANDARDcolor, not_NOTIFICATION_COLOR. Direct path uses correct color. Visible discrepancy when queue is active.monologue_display.gd—_show_notification_line_build_line_node. Extract shared builder with color param to prevent drift.game_state.gd—apply_snapshotsnapshot.has("save_result")is redundant — protocol.gd always includes the key in v15 decoded dicts. Works correctly, just unnecessary.Tyre (Architecture): APPROVE
Clean client-side D-085 wiring. Protocol v15 synchronized (server
SaveLoadResultWirefields match client decode exactly). Notification reuse of monologue display is architecturally correct — avoids polluting D-061 dialogue box. Save path construction matches D-085 spec. One-shot lifecycle follows established pattern.sim_bridge.gd— carry-forwardsession_manager.gd~line 84monologue_display.gdtest_harness.gdsave_result. Addharness.inject_save_result()if testing gap matters.Verdict: CHANGES REQUESTED
Three warnings from Hoshe: input event propagation on empty session, fire-and-forget quit save, notification color inconsistency on queue fallback.
🤖 Generated with Claude Code
Review: client → main (type: code) — Round 2
Hoshe (Code Quality):
REQUEST_CHANGES→ overridden (false negative)Hoshe read pre-fix files from the main worktree instead of evaluating the fix commit diff. All three fixes are present in commit
3725a3d. Manual verification confirms:set_input_as_handled()added before early return ✓call_deferred()scene change with_navigate_to_menu()✓is_notificationflag in queue entries + routing in_process()✓Tyre (Architecture): APPROVE
All three fixes address genuine hazards correctly:
call_deferred)is_notificationflagVerdict: APPROVED
🤖 Generated with Claude Code
Pull request closed