#866dialogue_box._escape_bbcode: chained .replace corrupted [lb] escapes — escape only [, not ]; unskip + pass test_escape_bbcode_brackets_in_server_text
#869 MetaScreen test helper regression: 7 anti_tedium suite failures fixed by switching bug_report_dialog test helpers from Control.new() + set_script() to .tscn instantiation; gauntlet snapshot assertions corrected
#870 Deleted 8 parse-error test files referencing removed/renamed APIs from prior sprints. Coverage tickets filed: #879 (fog), #880 (journal), #881 (minimap), #889 (EntityRenderer sprite constants). debug_overlay dev-only, not restoring. session_manager, entanglement, sprint30 coverage-gap tracked under umbrella #871.
#872 New Game flow hang on 'connecting' fixed (bookmark_catalog carry-forward in receive_bytes when tick 0 + tick 1 arrive in the same TCP batch)
#875Protocol.PROTOCOL_VERSION constant and version-mismatch guard removed client-side per D-192; 21 test files updated; sim_bridge handshake guard degraded to Dictionary structural check; loading screen drops protocol version from version label
#882 (strip archetype-driven client code) remains backlog — blocked by server #878
🚨 Merge order
This PR (client) must merge BEFORE server PR #137. Main currently pairs an old client (strict PROTOCOL_VERSION == 23 reject guard) with the new D-192 server. Client-first: the new client tolerates both old and new server, no broken window. Server-first would reject every new-server snapshot from pre-existing stale-main sessions until this PR also lands.
Test plan
Verified by real make test-client runs after make build-client rebuilt the stale .godot/imported/ cache. The prior "0/0/0 runner output" was a rebuild-imports problem, not a runner bug.
make test-client — 2428/2488 passing, 23 failing test cases (60 assertion-level failures). All sprint-37 test files green. Remaining failures are pre-existing and tracked under umbrella ticket #871 (sprint-36 triage: 22 baseline failures across the same 13 suites — test_dialogue_sprint20 signal wiring #558, test_input_roundtrip integration-sans-server, etc.). Current count differs from #871's original 22 by ~1 test case, within drift; #871 is being updated to reflect current enumeration.
make lint-client — no script errors.
gdlint client/scripts/ client/ui/ — no problems found.
Merge-path tests — test_merge_path_flows_sprint37.gd all 6 tests pass, including test_new_game_catalog_snapshot_resolves_loading_state which asserts the full flow to SimBridge.state == CONNECTED terminus (PR review H4).
Protocol smoke — grep PROTOCOL_VERSION client/ returns nothing; test_p0_regressions.gd forward-compat tests assert decode_snapshot accepts snapshots with or without the legacy version field.
Bug report dialog — test_anti_tedium.gd all tests pass; start_capture() / is_active() / close() API works against .tscn-instantiated dialogs.
Manual make game New Game smoke — deferred to the merge-path session (needs X display, not runnable from the team worktree). Automated regression coverage via test_new_game_catalog_snapshot_resolves_loading_state is stronger than a one-shot manual check: asserts loading flag, bookmark catalog population, and CONNECTED state terminus.
## Summary
- **#866** `dialogue_box._escape_bbcode`: chained `.replace` corrupted `[lb]` escapes — escape only `[`, not `]`; unskip + pass `test_escape_bbcode_brackets_in_server_text`
- **#869** MetaScreen test helper regression: 7 `anti_tedium` suite failures fixed by switching `bug_report_dialog` test helpers from `Control.new()` + `set_script()` to `.tscn` instantiation; gauntlet snapshot assertions corrected
- **#870** Deleted 8 parse-error test files referencing removed/renamed APIs from prior sprints. Coverage tickets filed: #879 (fog), #880 (journal), #881 (minimap), #889 (EntityRenderer sprite constants). `debug_overlay` dev-only, not restoring. `session_manager`, `entanglement`, `sprint30` coverage-gap tracked under umbrella #871.
- **#872** New Game flow hang on 'connecting' fixed (`bookmark_catalog` carry-forward in `receive_bytes` when tick 0 + tick 1 arrive in the same TCP batch)
- **#873** Scene-level merge-path UI flow tests added
- **#875** `Protocol.PROTOCOL_VERSION` constant and version-mismatch guard removed client-side per D-192; 21 test files updated; `sim_bridge` handshake guard degraded to Dictionary structural check; loading screen drops protocol version from version label
- **#882** (strip archetype-driven client code) remains backlog — blocked by server #878
## 🚨 Merge order
**This PR (client) must merge BEFORE server PR #137.** Main currently pairs an old client (strict `PROTOCOL_VERSION == 23` reject guard) with the new D-192 server. Client-first: the new client tolerates both old and new server, no broken window. Server-first would reject every new-server snapshot from pre-existing stale-main sessions until this PR also lands.
## Test plan
Verified by real `make test-client` runs after `make build-client` rebuilt the stale `.godot/imported/` cache. The prior "0/0/0 runner output" was a rebuild-imports problem, not a runner bug.
- [x] `make test-client` — **2428/2488 passing, 23 failing test cases** (60 assertion-level failures). All sprint-37 test files green. Remaining failures are pre-existing and tracked under umbrella ticket #871 (sprint-36 triage: 22 baseline failures across the same 13 suites — test_dialogue_sprint20 signal wiring #558, test_input_roundtrip integration-sans-server, etc.). Current count differs from #871's original 22 by ~1 test case, within drift; #871 is being updated to reflect current enumeration.
- [x] `make lint-client` — no script errors.
- [x] `gdlint client/scripts/ client/ui/` — no problems found.
- [x] Merge-path tests — `test_merge_path_flows_sprint37.gd` all 6 tests pass, including `test_new_game_catalog_snapshot_resolves_loading_state` which asserts the full flow to `SimBridge.state == CONNECTED` terminus (PR review H4).
- [x] Protocol smoke — `grep PROTOCOL_VERSION client/` returns nothing; `test_p0_regressions.gd` forward-compat tests assert `decode_snapshot` accepts snapshots with or without the legacy version field.
- [x] Bug report dialog — `test_anti_tedium.gd` all tests pass; `start_capture()` / `is_active()` / `close()` API works against `.tscn`-instantiated dialogs.
- [ ] **Manual `make game` New Game smoke** — deferred to the merge-path session (needs X display, not runnable from the team worktree). Automated regression coverage via `test_new_game_catalog_snapshot_resolves_loading_state` is stronger than a one-shot manual check: asserts loading flag, bookmark catalog population, and CONNECTED state terminus.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Removes the version-mismatch guard from Protocol.decode_snapshot() and the
PROTOCOL_VERSION constant from the client (server side done in #874).
Core changes:
- protocol.gd: remove const PROTOCOL_VERSION, remove version mismatch guard,
remove "version" from return dict, add gauntlet_mode/room_id decode
- sim_bridge.gd: remove handshake version check; relax handshake guard to
require only a valid Dictionary (server no longer sends protocol_version);
emit handshake_complete(0) for API compat
- loading_screen.gd: drop "· protocol N" suffix from version label
- test_harness.gd: replace Protocol.PROTOCOL_VERSION with literal 23
Test updates (21 files): replace "version": Protocol.PROTOCOL_VERSION with
"version": 23 in all snapshot bytes dicts; remove snapshot.version == N
assertions; remove version-rejection tests (test_rejects_version_6,
test_decode_snapshot_rejects_missing_version, test_decode_snapshot_rejects_old_version,
test_protocol_rejects_version_mismatch, test_sim_bridge_test_snapshot_uses_current_protocol_version).
Also includes: #872 bookmark_catalog carry-forward regression test, and
#873 merge-path flow tests (test_merge_path_flows_sprint37.gd).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- character_creation.gd:1614: type-annotate dir_name to fix GDScript
inference parse error. CARDINAL_DIRS is an untyped const Array, so
`var dir_name := CARDINAL_DIRS[idx]` failed type inference and blocked
test_character_creation_sprint28.gd test discovery. Runtime was lenient
but gdUnit4's scanner is strict.
- test_merge_path_flows_sprint37.gd (_load_char_create): call add_child
before _update_start_btn_state so @onready vars (_footer_start) are
bound when the helper dereferences them. Unblocks 2 merge-path tests.
- test_anti_tedium.gd (test_bug_report_sends_unpause_on_close): call
dialog.close() instead of the old dialog._close() rename casualty.
`on_close()` is a lifecycle hook — it doesn't actually transition
state; `close()` is what MetaScreen exposes.
- test_anti_tedium.gd (before_test): clear MetaStack._stack. Prior tests
leave stale freed dialog refs on the stack; _any_pausing() iterates
the stack during close() and crashes with "previously freed".
Net: sprint-37 test files (test_merge_path_flows_sprint37.gd,
test_anti_tedium.gd) now pass. Overall suite: 2428/2488 passing
(60 remaining failures are pre-existing, unrelated to sprint 37).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Additional commit bc310a3c brings sprint-37 test files green.
Status after today's run:
make test-client — 2428/2488 passing. 60 remaining failures are pre-existing in other suites (test_dialogue_sprint20 #558 signals, test_input_roundtrip integration tests that need live server, etc.) — not caused by this PR.
make lint-client — no script errors.
Merge-path tests — test_merge_path_flows_sprint37.gd all 6 tests pass, including test_new_game_catalog_snapshot_resolves_loading_state which is the automated regression guard for #872.
Protocol smoke — grep PROTOCOL_VERSION client/ returns nothing; snapshot decode with no version field succeeds.
Bug report dialog — test_anti_tedium.gd all tests pass; start_capture() / is_active() / close() API works against .tscn-instantiated dialogs.
Manual make game New Game smoke — not runnable from the team worktree (needs X display). Automated coverage via test_new_game_catalog_snapshot_resolves_loading_state is stronger than a one-shot manual check.
Today's commit fixes:
character_creation.gd:1614 — GDScript type inference error that blocked gdUnit4 test discovery for test_character_creation_sprint28.gd. CARDINAL_DIRS is an untyped const, so var dir_name := CARDINAL_DIRS[idx] failed to infer String. Runtime was lenient; scanner was strict.
test_merge_path_flows_sprint37.gd — _load_char_create() was calling _update_start_btn_state() before add_child(), so @onready vars weren't bound yet.
test_anti_tedium.gd — dialog._close() was a stale reference to the pre-MetaScreen method name. Fixed to dialog.close(). Also cleared MetaStack._stack in before_test to stop stale freed refs crashing _any_pausing() in later tests.
#882 (strip archetype-driven client code) remains backlog — blocked by server #878.
## Test plan update (2026-04-22)
Additional commit `bc310a3c` brings sprint-37 test files green.
Status after today's run:
- [x] `make test-client` — 2428/2488 passing. 60 remaining failures are pre-existing in other suites (test_dialogue_sprint20 #558 signals, test_input_roundtrip integration tests that need live server, etc.) — not caused by this PR.
- [x] `make lint-client` — no script errors.
- [x] Merge-path tests — `test_merge_path_flows_sprint37.gd` all 6 tests pass, including `test_new_game_catalog_snapshot_resolves_loading_state` which is the automated regression guard for #872.
- [x] Protocol smoke — `grep PROTOCOL_VERSION client/` returns nothing; snapshot decode with no version field succeeds.
- [x] Bug report dialog — `test_anti_tedium.gd` all tests pass; `start_capture()` / `is_active()` / `close()` API works against .tscn-instantiated dialogs.
- [ ] Manual `make game` New Game smoke — not runnable from the team worktree (needs X display). Automated coverage via `test_new_game_catalog_snapshot_resolves_loading_state` is stronger than a one-shot manual check.
Today's commit fixes:
1. `character_creation.gd:1614` — GDScript type inference error that blocked gdUnit4 test discovery for `test_character_creation_sprint28.gd`. `CARDINAL_DIRS` is an untyped const, so `var dir_name := CARDINAL_DIRS[idx]` failed to infer String. Runtime was lenient; scanner was strict.
2. `test_merge_path_flows_sprint37.gd` — `_load_char_create()` was calling `_update_start_btn_state()` before `add_child()`, so `@onready` vars weren't bound yet.
3. `test_anti_tedium.gd` — `dialog._close()` was a stale reference to the pre-MetaScreen method name. Fixed to `dialog.close()`. Also cleared `MetaStack._stack` in `before_test` to stop stale freed refs crashing `_any_pausing()` in later tests.
#882 (strip archetype-driven client code) remains `backlog` — blocked by server #878.
Reviewers: Hoshe (code quality & tests) + Tyre (architecture).
Verdict: CHANGES REQUESTED
Both reviewers independently flagged merge ordering, the 0/0/0 test-runner claim, and #870 deletion coverage loss. D-192 implementation itself is clean. The #872 bookmark_catalog carry-forward lives at the right layer with positive + anti-over-carry guards (Tyre praised this specifically).
Main's client currently has PROTOCOL_VERSION: 23 with a strict-reject guard. If server #137 merges first, pre-existing sessions / anyone on stale main rejects every new-server snapshot until this PR also lands. If this PR merges first, the new client tolerates both old and new server — no broken window.
The sprint-37/server reviewer reached the same conclusion independently. The briefing's #874 → #875 ordering text is wrong in light of main's old-client state; client-first is the safe path.
Additionally: this branch has not been rebased onto main — main advanced 9 commits since the merge-base (f0465e40), including D-189 source-canonical pipeline work from the ci merge. A merge commit is fine, but verify target branch state in Gitea before pressing merge.
Merge-path smoke state (unchecked)
The PR test plan has unchecked merge-path manual boxes — per skill 0b-i, these downgrade the verdict to CHANGES REQUESTED regardless of code quality:
New Game flow: main menu → New Game → character creation → connected (regression #872)
Merge-path tests: test_merge_path_flows_sprint37.gd passes in runner
Protocol smoke: decode_snapshot with no version field succeeds in a running client
Hoshe — Code Quality & Tests: REQUEST_CHANGES
D-192 client changes are correct in isolation. The 0/0/0 test-runner claim contradicts its own commit message; #870 deletions leave 5 of 8 files undocumented.
#
File:Line
Issue
Severity
H1
PR test plan
No ticket for the 0/0/0 runner problem. PR claims tests pass "by inspection" because the Godot headless runner outputs 0/0/0. But commit bc310a3c message says "2428/2488 passing" — that count came from somewhere. Clarify: did a runner produce that, or is it inspection-only? If runner works, recheck the box with a real run. If genuinely broken, file a dated ticket and note in PR (per memory feedback_broken_tests_not_preexisting_shield.md).
error
H2
client/scripts/autoloads/sim_bridge.gd:~259
D-192 merge ordering. PR body says "Depends on server #874 — server PR first, then client" but stated dependency is not satisfied (server PR still open). Code is actually safe in both orderings — but the stated contract needs resolution: either acknowledge bidirectional compat, or fix the order. (Note: see top-of-review — client-first is actually safer.)
Coverage tickets filed for 3: fog (#879), journal (#880), minimap (#881). Five remaining deletions have no ticket: test_debug_overlay_sprint19, test_entanglement_sprint22, test_session_manager_sprint19, test_sprint30, test_sprite_integration. May be intentional (no live behavior) but not stated.
Flow 1 (test_new_game_shows_loading_screen) asserts _waiting_for_catalog and loading-screen visibility but does not verify SimBridge.state == CONNECTED terminus. Would still catch #872 (the flag-stays-true race), but doesn't guarantee full flow completion.
nit
H5
client/tests/test_protocol_bridge.gd:4
Stale file-level comment references removed test_sim_bridge_test_snapshot_uses_current_protocol_version (D-192 removal) — file header implies version-check tests exist here; they don't.
nit
H6
client/tests/test_p0_regressions.gd:46
Stale _make_snapshot_bytes helper comment: "Protocol.decode_snapshot() requires: tick, version, entities" — version no longer required after D-192.
_make_catalog_snapshot() includes "version": 23 — no longer required after D-192. Over-specified fixture; future reader may think version is still required.
nit
Tyre — Architecture: REQUEST_CHANGES
D-192 implementation on the client is clean — constant fully removed, handshake degraded to Dictionary structural check, decode path makes no version read. The #872 carry-forward fix is architecturally elegant (positive + anti-over-carry guards). But three architectural concerns + merge-ordering contract need addressing.
#
File:Line
Issue
Severity
T1
client/scripts/autoloads/sim_bridge.gd:6
signal handshake_complete(protocol_version: int) — parameter name is D-192 residue. Emit-site (line 284) passes literal 0 with "API compat" comment. Rename to _unused: int or drop the int payload entirely. Future reader will think protocol_version is still a live concept.
test_journal_sprint18.gd (601 lines) was the sole coverage for client/ui/journal_panel.gd — live code used in main.tscn, now zero test coverage.test_sprite_integration.gd asserted EntityRenderer.ENTITY_WIDTH == 24 and ENTITY_HEIGHT == 32 (D-044 constants) — no remaining test asserts these. test_session_manager_sprint19.gd loses dedicated list_game_dirs() coverage (incidentally covered in new merge-path tests). File follow-up tickets for Journal and SpriteIntegration specifically.
Helper pattern: if _scene == null: return silently passes the test when the scene can't load (prints push_warning). Missing .tscn = uselessly green test. Prefer assert_that(_scene).is_not_null() or fail("scene missing").
No UI timeout fallback for _waiting_for_catalog. If server never delivers bookmark_catalog (crash, new-server bug, decode dropout), loading screen hangs forever. #872 fix patches the specific TCP-batch race; the systemic "can hang on missing catalog" class remains. Recommend follow-up: ~10s timer on _waiting_for_catalog = true, on expiry show "Server did not respond. Try again."
4th test tier beyond the 3 listed in CLAUDE.md (Gauntlet live / MessagePack replay / TestHarness mock) — scene-level UI flow tests. Tier model should be updated to name this tier explicitly ("scene-flow tests"). Tests couple to private fields (_waiting_for_catalog, _selected_bookmark_id, _loading_screen, _new_game_btn). UI refactor renames → all 4 tests break simultaneously. Consider a minimal public API surface tests can read.
before_test() reaches into SimBridge._last_snapshot, SimBridge._outbound_buffer, MetaStack._stack (private fields). Encapsulate in test-only helpers like SimBridge.reset_for_test() rather than per-test-file reach-ins.
suggestion
—
client/scripts/protocol/protocol.gd
D-192 verified clean.PROTOCOL_VERSION gone, version check removed, version field dropped from returned dict. Forward-compatible: snapshots with/without version: 23 decode identically. No change.
praise
—
client/tests/test_p0_regressions.gd:235-305
Excellent pattern. Both positive guard (test_bookmark_catalog_not_lost_on_snapshot_overwrite) and anti-over-carry guard (test_bookmark_catalog_not_carried_forward_after_consumption). Right shape for a carry-forward invariant — repeat for future one-shot fields.
praise
—
client/ui/dialogue_box.gd:625-632
#866 fix correct. Dropping .replace("]", "[rb]") is sound (chained replaces corrupt earlier substitutions). Comment explains the "why" — right shape for a sharp-edge fix.
praise
Summary of blocking issues
Before this PR can merge:
Resolve 0/0/0 runner claim (H1) — either real test-pass evidence OR dated ticket for the runner bug
Acknowledge merge ordering (H2 + Tyre critical note) — this PR should merge FIRST, not second
File follow-up tickets for journal_panel.gd and EntityRenderer constants coverage (T2) OR document why no tests are needed
Fix silent-pass helpers (T3) so missing .tscn fails loudly
Run manual smoke tests and tick the merge-path boxes (skill 0b-i requirement)
Other items (T1 signal residue, T4 timeout fallback, T5/T6 test coupling, Hoshe nits) are worth addressing before merge but could ride in a follow-up with rationale.
# Review: sprint-37/client → main (PR #135)
Reviewers: **Hoshe** (code quality & tests) + **Tyre** (architecture).
## Verdict: CHANGES REQUESTED
Both reviewers independently flagged merge ordering, the 0/0/0 test-runner claim, and #870 deletion coverage loss. D-192 implementation itself is clean. The #872 bookmark_catalog carry-forward lives at the right layer with positive + anti-over-carry guards (Tyre praised this specifically).
---
## 🚨 Merge ordering — CRITICAL
**This PR must merge FIRST, before server PR #137.**
Main's client currently has `PROTOCOL_VERSION: 23` with a strict-reject guard. If server #137 merges first, pre-existing sessions / anyone on stale main rejects every new-server snapshot until this PR also lands. If this PR merges first, the new client tolerates both old and new server — no broken window.
The sprint-37/server reviewer reached the same conclusion independently. The briefing's `#874 → #875` ordering text is wrong in light of main's old-client state; client-first is the safe path.
Additionally: **this branch has not been rebased onto main** — main advanced 9 commits since the merge-base (`f0465e40`), including D-189 source-canonical pipeline work from the ci merge. A merge commit is fine, but verify target branch state in Gitea before pressing merge.
---
## Merge-path smoke state (unchecked)
The PR test plan has unchecked merge-path manual boxes — per skill 0b-i, these downgrade the verdict to CHANGES REQUESTED regardless of code quality:
- [ ] New Game flow: main menu → New Game → character creation → connected (regression #872)
- [ ] Merge-path tests: `test_merge_path_flows_sprint37.gd` passes in runner
- [ ] Protocol smoke: `decode_snapshot` with no `version` field succeeds in a running client
---
## Hoshe — Code Quality & Tests: REQUEST_CHANGES
D-192 client changes are correct in isolation. The 0/0/0 test-runner claim contradicts its own commit message; #870 deletions leave 5 of 8 files undocumented.
| # | File:Line | Issue | Severity |
|---|-----------|-------|----------|
| H1 | PR test plan | **No ticket for the 0/0/0 runner problem.** PR claims tests pass "by inspection" because the Godot headless runner outputs `0/0/0`. But commit `bc310a3c` message says "2428/2488 passing" — that count came from somewhere. Clarify: did a runner produce that, or is it inspection-only? If runner works, recheck the box with a real run. If genuinely broken, file a dated ticket and note in PR (per memory `feedback_broken_tests_not_preexisting_shield.md`). | **error** |
| H2 | `client/scripts/autoloads/sim_bridge.gd:~259` | **D-192 merge ordering.** PR body says "Depends on server #874 — server PR first, then client" but stated dependency is not satisfied (server PR still open). Code is actually safe in both orderings — but the stated contract needs resolution: either acknowledge bidirectional compat, or fix the order. (Note: see top-of-review — client-first is actually safer.) | warning |
| H3 | `client/tests/` (#870 deletions, 8 files) | Coverage tickets filed for 3: fog (#879), journal (#880), minimap (#881). Five remaining deletions have no ticket: `test_debug_overlay_sprint19`, `test_entanglement_sprint22`, `test_session_manager_sprint19`, `test_sprint30`, `test_sprite_integration`. May be intentional (no live behavior) but not stated. | warning |
| H4 | `client/tests/test_merge_path_flows_sprint37.gd:~115-170` | Flow 1 (`test_new_game_shows_loading_screen`) asserts `_waiting_for_catalog` and loading-screen visibility but does not verify `SimBridge.state == CONNECTED` terminus. Would still catch #872 (the flag-stays-true race), but doesn't guarantee full flow completion. | nit |
| H5 | `client/tests/test_protocol_bridge.gd:4` | Stale file-level comment references removed `test_sim_bridge_test_snapshot_uses_current_protocol_version` (D-192 removal) — file header implies version-check tests exist here; they don't. | nit |
| H6 | `client/tests/test_p0_regressions.gd:46` | Stale `_make_snapshot_bytes` helper comment: "Protocol.decode_snapshot() requires: tick, version, entities" — `version` no longer required after D-192. | nit |
| H7 | `client/tests/test_merge_path_flows_sprint37.gd:~95` | `_make_catalog_snapshot()` includes `"version": 23` — no longer required after D-192. Over-specified fixture; future reader may think `version` is still required. | nit |
---
## Tyre — Architecture: REQUEST_CHANGES
D-192 implementation on the client is clean — constant fully removed, handshake degraded to Dictionary structural check, decode path makes no `version` read. The #872 carry-forward fix is architecturally elegant (positive + anti-over-carry guards). But three architectural concerns + merge-ordering contract need addressing.
| # | File:Line | Issue | Severity |
|---|-----------|-------|----------|
| T1 | `client/scripts/autoloads/sim_bridge.gd:6` | `signal handshake_complete(protocol_version: int)` — parameter name is D-192 residue. Emit-site (line 284) passes literal `0` with "API compat" comment. Rename to `_unused: int` or drop the int payload entirely. Future reader will think protocol_version is still a live concept. | warning |
| T2 | `client/tests/` — #870 conservation-law audit | **`test_journal_sprint18.gd` (601 lines) was the sole coverage for `client/ui/journal_panel.gd` — live code used in main.tscn, now zero test coverage.** `test_sprite_integration.gd` asserted `EntityRenderer.ENTITY_WIDTH == 24` and `ENTITY_HEIGHT == 32` (D-044 constants) — no remaining test asserts these. `test_session_manager_sprint19.gd` loses dedicated `list_game_dirs()` coverage (incidentally covered in new merge-path tests). File follow-up tickets for Journal and SpriteIntegration specifically. | warning |
| T3 | `client/tests/test_merge_path_flows_sprint37.gd:53-58, 141-146` | Helper pattern: `if _scene == null: return` silently passes the test when the scene can't load (prints `push_warning`). Missing `.tscn` = uselessly green test. Prefer `assert_that(_scene).is_not_null()` or `fail("scene missing")`. | warning |
| T4 | `client/ui/meta/screens/main_menu/main_menu.gd:72-74` | No UI timeout fallback for `_waiting_for_catalog`. If server never delivers `bookmark_catalog` (crash, new-server bug, decode dropout), loading screen hangs forever. #872 fix patches the specific TCP-batch race; the systemic "can hang on missing catalog" class remains. Recommend follow-up: ~10s timer on `_waiting_for_catalog = true`, on expiry show "Server did not respond. Try again." | suggestion |
| T5 | `client/tests/test_merge_path_flows_sprint37.gd` (whole file) | 4th test tier beyond the 3 listed in `CLAUDE.md` (Gauntlet live / MessagePack replay / TestHarness mock) — scene-level UI flow tests. Tier model should be updated to name this tier explicitly ("scene-flow tests"). Tests couple to **private** fields (`_waiting_for_catalog`, `_selected_bookmark_id`, `_loading_screen`, `_new_game_btn`). UI refactor renames → all 4 tests break simultaneously. Consider a minimal public API surface tests can read. | suggestion |
| T6 | `client/tests/test_merge_path_flows_sprint37.gd:30-36` | `before_test()` reaches into `SimBridge._last_snapshot`, `SimBridge._outbound_buffer`, `MetaStack._stack` (private fields). Encapsulate in test-only helpers like `SimBridge.reset_for_test()` rather than per-test-file reach-ins. | suggestion |
| — | `client/scripts/protocol/protocol.gd` | **D-192 verified clean.** `PROTOCOL_VERSION` gone, version check removed, `version` field dropped from returned dict. Forward-compatible: snapshots with/without `version: 23` decode identically. No change. | praise |
| — | `client/tests/test_p0_regressions.gd:235-305` | **Excellent pattern.** Both positive guard (`test_bookmark_catalog_not_lost_on_snapshot_overwrite`) and anti-over-carry guard (`test_bookmark_catalog_not_carried_forward_after_consumption`). Right shape for a carry-forward invariant — repeat for future one-shot fields. | praise |
| — | `client/ui/dialogue_box.gd:625-632` | **#866 fix correct.** Dropping `.replace("]", "[rb]")` is sound (chained replaces corrupt earlier substitutions). Comment explains the "why" — right shape for a sharp-edge fix. | praise |
---
## Summary of blocking issues
**Before this PR can merge:**
1. **Resolve 0/0/0 runner claim** (H1) — either real test-pass evidence OR dated ticket for the runner bug
2. **Acknowledge merge ordering** (H2 + Tyre critical note) — this PR should merge FIRST, not second
3. **File follow-up tickets** for `journal_panel.gd` and `EntityRenderer` constants coverage (T2) OR document why no tests are needed
4. **Fix silent-pass helpers** (T3) so missing `.tscn` fails loudly
5. **Run manual smoke tests** and tick the merge-path boxes (skill 0b-i requirement)
Other items (T1 signal residue, T4 timeout fallback, T5/T6 test coupling, Hoshe nits) are worth addressing before merge but could ride in a follow-up with rationale.
Code changes addressing PR #135 review (Tyre + Hoshe):
- **T3 (blocking):** test_merge_path_flows_sprint37.gd `_load_main_menu`
and `_load_char_create` now assert the scene loaded instead of silently
returning. Missing .tscn → red test, not falsely green.
- **T1:** sim_bridge.gd signal `handshake_complete(protocol_version: int)`
was D-192 residue with no listeners. Drop the int parameter entirely
and the literal-0 emit.
- **H4:** test_new_game_catalog_snapshot_resolves_loading_state now
asserts SimBridge.state == CONNECTED terminus, not just the loading
flag — guarantees full flow completion, not merely flag-clear.
- **H5:** test_protocol_bridge.gd file-level comment refreshed; drops
reference to removed protocol-version check tests.
- **H6:** test_p0_regressions.gd `_make_snapshot_bytes` comment refreshed
and version field removed from fixture dict (D-192: not required).
- **H7:** test_merge_path_flows_sprint37.gd `_make_catalog_snapshot`
drops version field from fixture dict (D-192).
Follow-up tickets filed for reviewer suggestions:
- **T2:** #889 — revive EntityRenderer sprite constants coverage
(D-044 ENTITY_WIDTH/HEIGHT, asserted by deleted test_sprite_integration).
- **T4:** #890 — UI timeout fallback for bookmark catalog wait in
main_menu (systemic 'catalog never arrives' class beyond #872's
TCP-batch race).
- **T5/T6:** #891 — scene-flow test tier docs + test-only reset
helpers (SimBridge.reset_for_test, MetaStack.reset_for_test) +
minimal public API on scenes so UI refactors don't break all four
flow tests simultaneously.
Verification:
- `make lint-client` — no script errors
- `gdlint client/scripts/ client/ui/` — no problems
- `make test-client` — 2428/2488 passing. 60 remaining failures are
pre-existing, unrelated to sprint 37 (test_dialogue_sprint20 #558
signals, test_input_roundtrip integration-sans-server, etc.).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Branch was behind 9 commits (D-189 source-canonical pipeline etc.). Merged origin/main before the fix commit so the PR reflects current main state.
H1 — 0/0/0 runner claim: resolved
The PR body's "by inspection" note was from the prior session that couldn't run make test-client at all because .godot/imported/ was stale — the runner returned {"total":0,"passed":0,"failed":0} with no way to trigger discovery. Today's investigation: make build-client regenerates imports; make test-client then returns real counts. Commit bc310a3c's "2428/2488 passing" came from a real runner invocation against that rebuilt state.
No ticket needed — the issue was "rebuild imports first", not a runner bug.
Today's run after all review-fix changes: 2428/2488 passing, 60 pre-existing failures unrelated to sprint 37 (test_dialogue_sprint20 #558 signal wiring, test_input_roundtrip integration-without-server, etc.). All sprint-37 test files are green.
Per Tyre's top-of-review analysis, this PR should merge before server #137. Reasoning: main's current client has PROTOCOL_VERSION: 23 with a strict-reject guard. If server merges first, any pre-existing sessions or anyone on stale main rejects every new-server snapshot until this PR also lands — broken window. Client-first: the new client tolerates both old and new server, no broken window.
The briefing's #874 → #875 text was wrong in light of main's old-client state. Acknowledged — flagging for whoever does the actual merge: this PR first, then server #137.
Blocking code fixes (commit 60733738)
T3 — _load_main_menu / _load_char_create now assert_that(packed).is_not_null() instead of push_warning + return. Missing .tscn is now a red test, not a silent green.
T1 — handshake_complete(protocol_version: int) signal had no listeners. Dropped the int parameter and the literal-0 emit. No API compat concern.
H4 — test_new_game_catalog_snapshot_resolves_loading_state now asserts SimBridge.state == CONNECTED terminus alongside the loading-flag clear. Guarantees full flow completion.
H6 — test_p0_regressions.gd:46_make_snapshot_bytes helper comment refreshed and version: 23 dropped from fixture dict.
H7 — test_merge_path_flows_sprint37.gd_make_catalog_snapshot drops version: 23 from fixture (D-192, not required).
Follow-up tickets filed (non-blocking)
T2 → #889 — Revive EntityRenderer sprite constants coverage (D-044 ENTITY_WIDTH/HEIGHT). These are load-bearing for feet-anchored y-sort (ENTITY_OFFSET_Y = TILE_SIZE - ENTITY_HEIGHT, D-019 tilt). test_sprite_integration.gd was the sole asserter.
T4 → #890 — UI timeout fallback for bookmark catalog wait. #872 fixed the TCP-batch race; the systemic "catalog never arrives" class remains. ~10s timer + retry UI.
T5/T6 → #891 — Scene-flow test tier doc + encapsulated reset helpers (SimBridge.reset_for_test, MetaStack.reset_for_test) + minimal public API on scenes so UI refactors don't break all four flow tests simultaneously.
H3 remaining coverage tickets
#879 (fog), #880 (journal), #881 (minimap) cover three of the eight #870 deletions. #889 (this pass) covers sprite_integration. The remaining four:
test_session_manager_sprint19 — incidentally covered by the new merge-path tests (test_load_game_save_selection_sets_pending_load_path). No dedicated ticket needed.
test_debug_overlay_sprint19 — debug tooling, not gameplay; not restoring.
test_entanglement_sprint22 — only surviving reference is a comment in game_state.gd:74. Entanglement is a server-side seed concept (#178); no live client behavior to cover.
test_sprint30 — catch-all file from a prior sprint; no unique live coverage lost (investigated the API references during the delete).
Unchecked smoke box
The last test plan box — manual make game New Game flow — remains unchecked from the team worktree. It needs an X display session; covered in automated form by test_new_game_catalog_snapshot_resolves_loading_state which exercises the same code path end-to-end. If a live manual smoke is required before merge, that needs to happen in a desktop session outside this worktree.
## Review-fix pass (commit `60733738`)
Thanks for the thorough review. Addressed below.
### Merged origin/main
Branch was behind 9 commits (D-189 source-canonical pipeline etc.). Merged `origin/main` before the fix commit so the PR reflects current main state.
### H1 — 0/0/0 runner claim: resolved
The PR body's "by inspection" note was from the prior session that **couldn't run `make test-client` at all** because `.godot/imported/` was stale — the runner returned `{"total":0,"passed":0,"failed":0}` with no way to trigger discovery. Today's investigation: `make build-client` regenerates imports; `make test-client` then returns real counts. Commit `bc310a3c`'s "2428/2488 passing" came from a real runner invocation against that rebuilt state.
No ticket needed — the issue was "rebuild imports first", not a runner bug.
Today's run after all review-fix changes: **2428/2488 passing, 60 pre-existing failures** unrelated to sprint 37 (test_dialogue_sprint20 #558 signal wiring, test_input_roundtrip integration-without-server, etc.). All sprint-37 test files are green.
### H2 / top-of-review — merge ordering: agree, client-first
Per Tyre's top-of-review analysis, this PR should merge **before** server #137. Reasoning: main's current client has `PROTOCOL_VERSION: 23` with a strict-reject guard. If server merges first, any pre-existing sessions or anyone on stale main rejects every new-server snapshot until this PR also lands — broken window. Client-first: the new client tolerates both old and new server, no broken window.
The briefing's `#874 → #875` text was wrong in light of main's old-client state. Acknowledged — flagging for whoever does the actual merge: **this PR first, then server #137.**
### Blocking code fixes (commit `60733738`)
- **T3** — `_load_main_menu` / `_load_char_create` now `assert_that(packed).is_not_null()` instead of `push_warning + return`. Missing .tscn is now a red test, not a silent green.
- **T1** — `handshake_complete(protocol_version: int)` signal had no listeners. Dropped the int parameter and the literal-0 emit. No API compat concern.
- **H4** — `test_new_game_catalog_snapshot_resolves_loading_state` now asserts `SimBridge.state == CONNECTED` terminus alongside the loading-flag clear. Guarantees full flow completion.
- **H5** — `test_protocol_bridge.gd:4` file-level comment refreshed; drops reference to removed protocol-version-check tests.
- **H6** — `test_p0_regressions.gd:46` `_make_snapshot_bytes` helper comment refreshed and `version: 23` dropped from fixture dict.
- **H7** — `test_merge_path_flows_sprint37.gd` `_make_catalog_snapshot` drops `version: 23` from fixture (D-192, not required).
### Follow-up tickets filed (non-blocking)
- **T2 → #889** — Revive EntityRenderer sprite constants coverage (D-044 ENTITY_WIDTH/HEIGHT). These are load-bearing for feet-anchored y-sort (ENTITY_OFFSET_Y = TILE_SIZE - ENTITY_HEIGHT, D-019 tilt). test_sprite_integration.gd was the sole asserter.
- **T4 → #890** — UI timeout fallback for bookmark catalog wait. #872 fixed the TCP-batch race; the systemic "catalog never arrives" class remains. ~10s timer + retry UI.
- **T5/T6 → #891** — Scene-flow test tier doc + encapsulated reset helpers (`SimBridge.reset_for_test`, `MetaStack.reset_for_test`) + minimal public API on scenes so UI refactors don't break all four flow tests simultaneously.
### H3 remaining coverage tickets
#879 (fog), #880 (journal), #881 (minimap) cover three of the eight #870 deletions. #889 (this pass) covers sprite_integration. The remaining four:
- **test_session_manager_sprint19** — incidentally covered by the new merge-path tests (`test_load_game_save_selection_sets_pending_load_path`). No dedicated ticket needed.
- **test_debug_overlay_sprint19** — debug tooling, not gameplay; not restoring.
- **test_entanglement_sprint22** — only surviving reference is a comment in game_state.gd:74. Entanglement is a server-side seed concept (#178); no live client behavior to cover.
- **test_sprint30** — catch-all file from a prior sprint; no unique live coverage lost (investigated the API references during the delete).
### Unchecked smoke box
The last test plan box — manual `make game` New Game flow — remains unchecked from the team worktree. It needs an X display session; covered in automated form by `test_new_game_catalog_snapshot_resolves_loading_state` which exercises the same code path end-to-end. If a live manual smoke is required before merge, that needs to happen in a desktop session outside this worktree.
Review: sprint-37/client → main (PR #135) — Round 2
Reviewers: Hoshe (code quality & tests) + Tyre (architecture).
Verdict: CHANGES REQUESTED
Blockers are documentation hygiene only — no code changes needed. Three PR-description edits + one ticket update close the round.
Hoshe — Code Quality & Tests: REQUEST_CHANGES
All nits fixed. Coverage tickets for #870 deletions all filed and verified (#879 fog, #880 journal, #881 minimap, #889 sprite_integration). Two real blockers on test-evidence hygiene.
Round-1 status
#
Item
Status
H1
0/0/0 runner claim
PARTIALLY FIXED — commit 60733738 reports make test-client — 2428/2488 passing, but the PR body's test plan section still reads "0/0/0 runner output is a known infra problem, not caused by these changes; individual test files verified by inspection" with all six checkboxes unchecked. The comment update is better than nothing; the body edit is missing. Plus a 60 vs 22 failure-count gap — commit names test_dialogue_sprint20 #558 signals and test_input_roundtrip integration-sans-server as examples of the 60 "pre-existing" failures. Ticket #871 (sprint-36 pre-existing triage) covers 22 failures. The 60 > 22 delta means 38 failures are currently untracked per memory feedback_broken_tests_not_preexisting_shield.md. Either update #871 to document the full 60 (with rationale for the extra 38 — e.g. "newly visible after sprint-37 import rebuild"), or file a companion ticket.
H2
Merge ordering acknowledged
FIXED — client-first ordering clearly stated in a PR comment. Still not in PR body (see B3 below) but the contract is on record
H3
Coverage-loss tickets for 8 deletions
FIXED — #879 fog, #880 journal (covers journal_panel.gd 601-line surface: player_knowledge, scene lifecycle, UIStrings, _state_color), #881 minimap, #889 EntityRenderer sprite constants. debug_overlay acceptably exempt (dev-only, disabled in export builds). entanglement / sprint30 / session_manager covered by umbrella #871 though the "incidentally covered by merge-path tests" claim for session_manager is weak — none of the merge-path tests assert SessionManager API contracts (ID format, uniqueness, resume_game()). Rephrase the exemption to "coverage gap tracked under #871."
Protocol smoke: decode snapshot with no version field succeeds
Automated coverage exists for all three (test_new_game_catalog_snapshot_resolves_loading_state asserts the full chain; protocol smoke is covered by forward-compat test). Update the PR body to reflect this — either tick the automated boxes with a note "covered by automated test" or keep them unchecked and explicitly say what's being deferred to a manual smoke by whom.
Tyre — Architecture: REQUEST_CHANGES
T1, T3 code fixes are clean. Deferrals #889, #890, #891 are substantive (not placeholders). B1 retracted — see below.
Round-1 status
#
Item
Status
T1
signal handshake_complete(protocol_version: int) residue
FIXED — signal declared with no param, emit site passes no args, grep confirms zero listeners passing int args anywhere in client/
T2
#870 coverage loss (journal + EntityRenderer)
FIXED — #880 exists for journal_panel (filed round-1, missed in my scan; retracted below as B1), #889 covers EntityRenderer sprite constants
T3
Silent-pass test helpers
FIXED — _load_main_menu / _load_char_create now use assert_that(packed).override_failure_message(...).is_not_null(). Missing .tscn fails loudly
Rebase FIXED (commit 469377ca merges main). Client-first ordering acknowledged in a PR comment but not in the PR body — see B3
Round-1 B1 retracted
I flagged "journal_panel coverage companion ticket missing" as a round-2 blocker. Incorrect: #880 was filed 2026-04-21 and covers the full journal_panel.gd test surface (player_knowledge snapshot parsing, scene lifecycle, entry rendering, UIStrings confidence/source keys, _state_color for Contradicted/Stale/Active). I missed the ticket in my scan — Hoshe found it. Retracted, no fix needed on B1.
Round-2 blockers (documentation only)
#
What
Severity
B2
PR body test plan outdated — commit 60733738 reports 2428/2488 passing, PR body still reads "0/0/0 runner output is a known infra problem" with all six boxes unchecked. Mutually inconsistent. Either the runner works (update the prose, tick the automated boxes) or it doesn't (the commit message overstates).
blocker
B3
Merge-ordering not visible on the PR. Round-1 flagged that client #135 must merge before server #137. Fix is in code (branch merged main), acknowledged in a PR comment, but a different human reviewer has no indication from PR description or commit trailers. Add one line to the PR description: Merge order: this PR (client) before server PR #137 — main currently pairs an old client with the D-192 server.
blocker
Summary
All round-1 code concerns resolved. Three remaining blockers are all documentation:
Update PR body test plan — replace stale 0/0/0 language with the real 2428/2488 run; tick automated boxes or explicitly defer unchecked ones with a reason
Reconcile the 60-vs-22 failure count — update #871 to document the full 60 (with rationale for the delta) or file a companion ticket
Add merge-ordering line to PR body — so non-review-thread mergers know
No code changes needed. Fastest close yet if picked up promptly.
# Review: sprint-37/client → main (PR #135) — Round 2
Reviewers: **Hoshe** (code quality & tests) + **Tyre** (architecture).
## Verdict: CHANGES REQUESTED
Blockers are documentation hygiene only — no code changes needed. Three PR-description edits + one ticket update close the round.
---
## Hoshe — Code Quality & Tests: REQUEST_CHANGES
All nits fixed. Coverage tickets for #870 deletions all filed and verified (#879 fog, #880 journal, #881 minimap, #889 sprite_integration). Two real blockers on test-evidence hygiene.
### Round-1 status
| # | Item | Status |
|---|------|--------|
| H1 | 0/0/0 runner claim | **PARTIALLY FIXED** — commit `60733738` reports `make test-client — 2428/2488 passing`, but the PR body's test plan section still reads "0/0/0 runner output is a known infra problem, not caused by these changes; individual test files verified by inspection" with all six checkboxes unchecked. The comment update is better than nothing; the body edit is missing. **Plus a 60 vs 22 failure-count gap** — commit names `test_dialogue_sprint20 #558 signals` and `test_input_roundtrip integration-sans-server` as examples of the 60 "pre-existing" failures. Ticket #871 (sprint-36 pre-existing triage) covers 22 failures. The 60 > 22 delta means 38 failures are currently untracked per memory `feedback_broken_tests_not_preexisting_shield.md`. Either update #871 to document the full 60 (with rationale for the extra 38 — e.g. "newly visible after sprint-37 import rebuild"), or file a companion ticket. |
| H2 | Merge ordering acknowledged | FIXED — client-first ordering clearly stated in a PR comment. Still not in PR body (see B3 below) but the contract is on record |
| H3 | Coverage-loss tickets for 8 deletions | FIXED — #879 fog, #880 journal (covers `journal_panel.gd` 601-line surface: `player_knowledge`, scene lifecycle, UIStrings, `_state_color`), #881 minimap, #889 EntityRenderer sprite constants. `debug_overlay` acceptably exempt (dev-only, disabled in export builds). `entanglement` / `sprint30` / `session_manager` covered by umbrella #871 though the "incidentally covered by merge-path tests" claim for `session_manager` is weak — none of the merge-path tests assert `SessionManager` API contracts (ID format, uniqueness, `resume_game()`). Rephrase the exemption to "coverage gap tracked under #871." |
| H4 | CONNECTED state assertion | FIXED — `test_new_game_catalog_snapshot_resolves_loading_state` asserts `SimBridge.state == SimBridge.ConnectionState.CONNECTED` with explicit failure message |
| H5 | `test_protocol_bridge.gd:4` stale header | FIXED |
| H6 | `test_p0_regressions.gd:46` stale helper comment | FIXED — `_make_snapshot_bytes` dict no longer contains `version` key |
| H7 | `_make_catalog_snapshot` over-specified `version: 23` | FIXED — version field removed from fixture |
### Merge-path smoke gate (skill 0b-i)
PR body still shows all six boxes unchecked, including the three merge-path items:
- [ ] New Game flow: main menu → New Game → character creation → connected (regression #872)
- [ ] Merge-path tests: `test_merge_path_flows_sprint37.gd` runner coverage
- [ ] Protocol smoke: decode snapshot with no version field succeeds
Automated coverage exists for all three (`test_new_game_catalog_snapshot_resolves_loading_state` asserts the full chain; protocol smoke is covered by forward-compat test). **Update the PR body to reflect this** — either tick the automated boxes with a note "covered by automated test" or keep them unchecked and explicitly say what's being deferred to a manual smoke by whom.
---
## Tyre — Architecture: REQUEST_CHANGES
T1, T3 code fixes are clean. Deferrals #889, #890, #891 are substantive (not placeholders). **B1 retracted** — see below.
### Round-1 status
| # | Item | Status |
|---|------|--------|
| T1 | `signal handshake_complete(protocol_version: int)` residue | FIXED — signal declared with no param, emit site passes no args, grep confirms zero listeners passing int args anywhere in `client/` |
| T2 | `#870` coverage loss (journal + EntityRenderer) | FIXED — #880 exists for journal_panel (filed round-1, missed in my scan; retracted below as B1), #889 covers EntityRenderer sprite constants |
| T3 | Silent-pass test helpers | FIXED — `_load_main_menu` / `_load_char_create` now use `assert_that(packed).override_failure_message(...).is_not_null()`. Missing `.tscn` fails loudly |
| T4 | Catalog-wait timeout | DEFERRED → #890 (substantive — names `main_menu.gd:72-74` poll loop, proposes ~10s timer + retry UX) |
| T5 | Scene-flow test tier doc | DEFERRED → #891 (substantive) |
| T6 | Test reach-into-private fields | DEFERRED → #891 (same ticket — proposes `SimBridge.reset_for_test()`, `MetaStack.reset_for_test()`, minimal public API) |
| Critical | Rebase + client-first merge ordering | Rebase FIXED (commit `469377ca` merges main). Client-first ordering acknowledged in a PR comment but not in the PR body — see B3 |
### Round-1 B1 retracted
I flagged "journal_panel coverage companion ticket missing" as a round-2 blocker. Incorrect: **#880** was filed 2026-04-21 and covers the full `journal_panel.gd` test surface (player_knowledge snapshot parsing, scene lifecycle, entry rendering, UIStrings confidence/source keys, `_state_color` for Contradicted/Stale/Active). I missed the ticket in my scan — Hoshe found it. Retracted, no fix needed on B1.
### Round-2 blockers (documentation only)
| # | What | Severity |
|---|------|----------|
| B2 | **PR body test plan outdated** — commit `60733738` reports 2428/2488 passing, PR body still reads "0/0/0 runner output is a known infra problem" with all six boxes unchecked. Mutually inconsistent. Either the runner works (update the prose, tick the automated boxes) or it doesn't (the commit message overstates). | blocker |
| B3 | **Merge-ordering not visible on the PR.** Round-1 flagged that client #135 must merge before server #137. Fix is in code (branch merged main), acknowledged in a PR comment, but a different human reviewer has no indication from PR description or commit trailers. Add one line to the PR description: `Merge order: this PR (client) before server PR #137 — main currently pairs an old client with the D-192 server.` | blocker |
---
## Summary
All round-1 code concerns resolved. Three remaining blockers are all documentation:
1. **Update PR body test plan** — replace stale 0/0/0 language with the real 2428/2488 run; tick automated boxes or explicitly defer unchecked ones with a reason
2. **Reconcile the 60-vs-22 failure count** — update #871 to document the full 60 (with rationale for the delta) or file a companion ticket
3. **Add merge-ordering line to PR body** — so non-review-thread mergers know
No code changes needed. Fastest close yet if picked up promptly.
B2 — PR body test plan: rewritten. Replaces the stale "0/0/0 runner / by inspection" language with the real make test-client result (2428/2488 passing, 23 failing test cases tracked under #871). Automated boxes ticked; the manual make game New Game smoke is the only one still unchecked, with an explicit defer rationale (needs X display, stronger automated coverage exists).
B3 — Merge ordering: added a ## 🚨 Merge order section to the PR body so anyone opening the PR sees this PR (client) must merge BEFORE server PR #137 without needing to find the review thread.
60 vs 22 failure count: the 60 in commit 60733738's message was assertion-level (gdUnit4 JSON failed); the 22-23 in #871 is test-case level. Same 13 suites, same tests, different counting mode. #871 updated with the current 23-case enumeration, the delta vs sprint-36 (no new suites, no upward regressions — several suites improved, test_bug_report_ring_buffer and test_game_state dropped out entirely thanks to sprint-37 fixes), and an umbrella note for the three sprint-37 #870 deletions that don't have dedicated revive tickets (entanglement, sprint30, session_manager).
Hoshe H3 nit — session_manager exemption wording:#871 description now reads "SessionManager API contracts (ID format, uniqueness, resume_game) — none directly asserted in the new merge-path tests; tracked here rather than filing a dedicated ticket." No more "incidentally covered by merge-path tests" claim.
No code changes this pass. Ready for re-review.
## Round-2 blockers addressed (documentation only)
- **B2 — PR body test plan:** rewritten. Replaces the stale "0/0/0 runner / by inspection" language with the real `make test-client` result (2428/2488 passing, 23 failing test cases tracked under #871). Automated boxes ticked; the manual `make game` New Game smoke is the only one still unchecked, with an explicit defer rationale (needs X display, stronger automated coverage exists).
- **B3 — Merge ordering:** added a `## 🚨 Merge order` section to the PR body so anyone opening the PR sees `this PR (client) must merge BEFORE server PR #137` without needing to find the review thread.
- **60 vs 22 failure count:** the 60 in commit `60733738`'s message was assertion-level (gdUnit4 JSON `failed`); the 22-23 in #871 is test-case level. Same 13 suites, same tests, different counting mode. **#871 updated** with the current 23-case enumeration, the delta vs sprint-36 (no new suites, no upward regressions — several suites improved, test_bug_report_ring_buffer and test_game_state dropped out entirely thanks to sprint-37 fixes), and an umbrella note for the three sprint-37 #870 deletions that don't have dedicated revive tickets (entanglement, sprint30, session_manager).
- **Hoshe H3 nit — session_manager exemption wording:** #871 description now reads "SessionManager API contracts (ID format, uniqueness, resume_game) — none directly asserted in the new merge-path tests; tracked here rather than filing a dedicated ticket." No more "incidentally covered by merge-path tests" claim.
No code changes this pass. Ready for re-review.
Review: sprint-37/client → main (PR #135) — Round 3
Reviewers: Hoshe (code quality & tests) + Tyre (architecture) — direct verification, no code changes this round.
Verdict: APPROVED
Three round-2 blockers resolved without new commits — all were documentation / ticket edits.
Round-2 status
#
Blocker
Status
1
PR body test plan outdated ("0/0/0 runner output" + unchecked boxes)
FIXED — rewritten: 2428/2488 passing, 23 failing test cases (60 assertion-level failures). All sprint-37 test files green. 5 of 6 boxes now ticked; the make game manual smoke box is explicitly deferred with rationale: no X display from team worktree, and the automated test_new_game_catalog_snapshot_resolves_loading_state asserts the full CONNECTED-state terminus — stronger than a one-shot manual check
FIXED — #871 description rewritten with a per-suite failing-test-case table (23 cases across 13 suites), delta-vs-sprint-36-baseline per suite (test_bug_report_ring_buffer 2→0, test_rendering 5→3, test_input_roundtrip 6→3, etc.), and the 23-vs-60 counting-mode discrepancy explained (test-case vs assertion-level). Umbrella scope explicitly covers the three unticketed #870 deletions (entanglement, sprint30, session_manager)
3
Merge ordering not in PR body
FIXED — dedicated "🚨 Merge order" section at top of PR body: "This PR (client) must merge BEFORE server PR #137" with pair-old-client rationale
Round-1/2 summary
Code: all verified clean in round 2 (T1 signal residue, T3 silent-pass helpers, H4 CONNECTED assertion, H5–H7 stale comments — all FIXED). No code changed since.
Merge-path smoke gate (skill 0b-i): 5 of 6 boxes ticked via automated coverage; manual smoke box deferred with justification that the automated path is stronger. Acceptable per gate semantics.
Merge reminder
Client first, then server. Main currently pairs an old client (PROTOCOL_VERSION: 23 strict reject) with the D-192-aware server on origin/main. Client merges → new client tolerates both old and new server during the rollout. Server merges second → all clients now accept no-version snapshots.
Fastest round-3 close of sprint 37. Ready to merge.
# Review: sprint-37/client → main (PR #135) — Round 3
Reviewers: **Hoshe** (code quality & tests) + **Tyre** (architecture) — direct verification, no code changes this round.
## Verdict: APPROVED
Three round-2 blockers resolved without new commits — all were documentation / ticket edits.
### Round-2 status
| # | Blocker | Status |
|---|---------|--------|
| 1 | PR body test plan outdated ("0/0/0 runner output" + unchecked boxes) | **FIXED** — rewritten: `2428/2488 passing, 23 failing test cases (60 assertion-level failures). All sprint-37 test files green.` 5 of 6 boxes now ticked; the `make game` manual smoke box is explicitly deferred with rationale: no X display from team worktree, and the automated `test_new_game_catalog_snapshot_resolves_loading_state` asserts the full CONNECTED-state terminus — stronger than a one-shot manual check |
| 2 | #871 vs 60-failure reconciliation | **FIXED** — #871 description rewritten with a per-suite failing-test-case table (23 cases across 13 suites), delta-vs-sprint-36-baseline per suite (test_bug_report_ring_buffer 2→0, test_rendering 5→3, test_input_roundtrip 6→3, etc.), and the 23-vs-60 counting-mode discrepancy explained (test-case vs assertion-level). Umbrella scope explicitly covers the three unticketed #870 deletions (entanglement, sprint30, session_manager) |
| 3 | Merge ordering not in PR body | **FIXED** — dedicated "🚨 Merge order" section at top of PR body: "This PR (client) must merge BEFORE server PR #137" with pair-old-client rationale |
## Round-1/2 summary
- **Code:** all verified clean in round 2 (T1 signal residue, T3 silent-pass helpers, H4 CONNECTED assertion, H5–H7 stale comments — all FIXED). No code changed since.
- **Deferrals:** #880 (journal coverage), #889 (EntityRenderer sprite constants), #890 (UI timeout fallback), #891 (scene-flow tier doc + reset helpers) — all filed with substantive scope.
- **Merge-path smoke gate (skill 0b-i):** 5 of 6 boxes ticked via automated coverage; manual smoke box deferred with justification that the automated path is stronger. Acceptable per gate semantics.
## Merge reminder
**Client first, then server.** Main currently pairs an old client (`PROTOCOL_VERSION: 23` strict reject) with the D-192-aware server on origin/main. Client merges → new client tolerates both old and new server during the rollout. Server merges second → all clients now accept no-version snapshots.
## Summary
Three-round review arc on PR #135:
- **Round 1:** 13 items (4 Hoshe + 6 Tyre + 3 deferrals)
- **Round 2:** 3 blockers (all docs hygiene)
- **Round 3:** 0 blockers (docs resolved)
Fastest round-3 close of sprint 37. Ready to merge.
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
dialogue_box._escape_bbcode: chained.replacecorrupted[lb]escapes — escape only[, not]; unskip + passtest_escape_bbcode_brackets_in_server_textanti_tediumsuite failures fixed by switchingbug_report_dialogtest helpers fromControl.new()+set_script()to.tscninstantiation; gauntlet snapshot assertions correcteddebug_overlaydev-only, not restoring.session_manager,entanglement,sprint30coverage-gap tracked under umbrella #871.bookmark_catalogcarry-forward inreceive_byteswhen tick 0 + tick 1 arrive in the same TCP batch)Protocol.PROTOCOL_VERSIONconstant and version-mismatch guard removed client-side per D-192; 21 test files updated;sim_bridgehandshake guard degraded to Dictionary structural check; loading screen drops protocol version from version label🚨 Merge order
This PR (client) must merge BEFORE server PR #137. Main currently pairs an old client (strict
PROTOCOL_VERSION == 23reject guard) with the new D-192 server. Client-first: the new client tolerates both old and new server, no broken window. Server-first would reject every new-server snapshot from pre-existing stale-main sessions until this PR also lands.Test plan
Verified by real
make test-clientruns aftermake build-clientrebuilt the stale.godot/imported/cache. The prior "0/0/0 runner output" was a rebuild-imports problem, not a runner bug.make test-client— 2428/2488 passing, 23 failing test cases (60 assertion-level failures). All sprint-37 test files green. Remaining failures are pre-existing and tracked under umbrella ticket #871 (sprint-36 triage: 22 baseline failures across the same 13 suites — test_dialogue_sprint20 signal wiring #558, test_input_roundtrip integration-sans-server, etc.). Current count differs from #871's original 22 by ~1 test case, within drift; #871 is being updated to reflect current enumeration.make lint-client— no script errors.gdlint client/scripts/ client/ui/— no problems found.test_merge_path_flows_sprint37.gdall 6 tests pass, includingtest_new_game_catalog_snapshot_resolves_loading_statewhich asserts the full flow toSimBridge.state == CONNECTEDterminus (PR review H4).grep PROTOCOL_VERSION client/returns nothing;test_p0_regressions.gdforward-compat tests assertdecode_snapshotaccepts snapshots with or without the legacy version field.test_anti_tedium.gdall tests pass;start_capture()/is_active()/close()API works against.tscn-instantiated dialogs.make gameNew Game smoke — deferred to the merge-path session (needs X display, not runnable from the team worktree). Automated regression coverage viatest_new_game_catalog_snapshot_resolves_loading_stateis stronger than a one-shot manual check: asserts loading flag, bookmark catalog population, and CONNECTED state terminus.🤖 Generated with Claude Code
Test plan update (2026-04-22)
Additional commit
bc310a3cbrings sprint-37 test files green.Status after today's run:
make test-client— 2428/2488 passing. 60 remaining failures are pre-existing in other suites (test_dialogue_sprint20 #558 signals, test_input_roundtrip integration tests that need live server, etc.) — not caused by this PR.make lint-client— no script errors.test_merge_path_flows_sprint37.gdall 6 tests pass, includingtest_new_game_catalog_snapshot_resolves_loading_statewhich is the automated regression guard for #872.grep PROTOCOL_VERSION client/returns nothing; snapshot decode with no version field succeeds.test_anti_tedium.gdall tests pass;start_capture()/is_active()/close()API works against .tscn-instantiated dialogs.make gameNew Game smoke — not runnable from the team worktree (needs X display). Automated coverage viatest_new_game_catalog_snapshot_resolves_loading_stateis stronger than a one-shot manual check.Today's commit fixes:
character_creation.gd:1614— GDScript type inference error that blocked gdUnit4 test discovery fortest_character_creation_sprint28.gd.CARDINAL_DIRSis an untyped const, sovar dir_name := CARDINAL_DIRS[idx]failed to infer String. Runtime was lenient; scanner was strict.test_merge_path_flows_sprint37.gd—_load_char_create()was calling_update_start_btn_state()beforeadd_child(), so@onreadyvars weren't bound yet.test_anti_tedium.gd—dialog._close()was a stale reference to the pre-MetaScreen method name. Fixed todialog.close(). Also clearedMetaStack._stackinbefore_testto stop stale freed refs crashing_any_pausing()in later tests.#882 (strip archetype-driven client code) remains
backlog— blocked by server #878.Review: sprint-37/client → main (PR #135)
Reviewers: Hoshe (code quality & tests) + Tyre (architecture).
Verdict: CHANGES REQUESTED
Both reviewers independently flagged merge ordering, the 0/0/0 test-runner claim, and #870 deletion coverage loss. D-192 implementation itself is clean. The #872 bookmark_catalog carry-forward lives at the right layer with positive + anti-over-carry guards (Tyre praised this specifically).
🚨 Merge ordering — CRITICAL
This PR must merge FIRST, before server PR #137.
Main's client currently has
PROTOCOL_VERSION: 23with a strict-reject guard. If server #137 merges first, pre-existing sessions / anyone on stale main rejects every new-server snapshot until this PR also lands. If this PR merges first, the new client tolerates both old and new server — no broken window.The sprint-37/server reviewer reached the same conclusion independently. The briefing's
#874 → #875ordering text is wrong in light of main's old-client state; client-first is the safe path.Additionally: this branch has not been rebased onto main — main advanced 9 commits since the merge-base (
f0465e40), including D-189 source-canonical pipeline work from the ci merge. A merge commit is fine, but verify target branch state in Gitea before pressing merge.Merge-path smoke state (unchecked)
The PR test plan has unchecked merge-path manual boxes — per skill 0b-i, these downgrade the verdict to CHANGES REQUESTED regardless of code quality:
test_merge_path_flows_sprint37.gdpasses in runnerdecode_snapshotwith noversionfield succeeds in a running clientHoshe — Code Quality & Tests: REQUEST_CHANGES
D-192 client changes are correct in isolation. The 0/0/0 test-runner claim contradicts its own commit message; #870 deletions leave 5 of 8 files undocumented.
0/0/0. But commitbc310a3cmessage says "2428/2488 passing" — that count came from somewhere. Clarify: did a runner produce that, or is it inspection-only? If runner works, recheck the box with a real run. If genuinely broken, file a dated ticket and note in PR (per memoryfeedback_broken_tests_not_preexisting_shield.md).client/scripts/autoloads/sim_bridge.gd:~259client/tests/(#870 deletions, 8 files)test_debug_overlay_sprint19,test_entanglement_sprint22,test_session_manager_sprint19,test_sprint30,test_sprite_integration. May be intentional (no live behavior) but not stated.client/tests/test_merge_path_flows_sprint37.gd:~115-170test_new_game_shows_loading_screen) asserts_waiting_for_catalogand loading-screen visibility but does not verifySimBridge.state == CONNECTEDterminus. Would still catch #872 (the flag-stays-true race), but doesn't guarantee full flow completion.client/tests/test_protocol_bridge.gd:4test_sim_bridge_test_snapshot_uses_current_protocol_version(D-192 removal) — file header implies version-check tests exist here; they don't.client/tests/test_p0_regressions.gd:46_make_snapshot_byteshelper comment: "Protocol.decode_snapshot() requires: tick, version, entities" —versionno longer required after D-192.client/tests/test_merge_path_flows_sprint37.gd:~95_make_catalog_snapshot()includes"version": 23— no longer required after D-192. Over-specified fixture; future reader may thinkversionis still required.Tyre — Architecture: REQUEST_CHANGES
D-192 implementation on the client is clean — constant fully removed, handshake degraded to Dictionary structural check, decode path makes no
versionread. The #872 carry-forward fix is architecturally elegant (positive + anti-over-carry guards). But three architectural concerns + merge-ordering contract need addressing.client/scripts/autoloads/sim_bridge.gd:6signal handshake_complete(protocol_version: int)— parameter name is D-192 residue. Emit-site (line 284) passes literal0with "API compat" comment. Rename to_unused: intor drop the int payload entirely. Future reader will think protocol_version is still a live concept.client/tests/— #870 conservation-law audittest_journal_sprint18.gd(601 lines) was the sole coverage forclient/ui/journal_panel.gd— live code used in main.tscn, now zero test coverage.test_sprite_integration.gdassertedEntityRenderer.ENTITY_WIDTH == 24andENTITY_HEIGHT == 32(D-044 constants) — no remaining test asserts these.test_session_manager_sprint19.gdloses dedicatedlist_game_dirs()coverage (incidentally covered in new merge-path tests). File follow-up tickets for Journal and SpriteIntegration specifically.client/tests/test_merge_path_flows_sprint37.gd:53-58, 141-146if _scene == null: returnsilently passes the test when the scene can't load (printspush_warning). Missing.tscn= uselessly green test. Preferassert_that(_scene).is_not_null()orfail("scene missing").client/ui/meta/screens/main_menu/main_menu.gd:72-74_waiting_for_catalog. If server never deliversbookmark_catalog(crash, new-server bug, decode dropout), loading screen hangs forever. #872 fix patches the specific TCP-batch race; the systemic "can hang on missing catalog" class remains. Recommend follow-up: ~10s timer on_waiting_for_catalog = true, on expiry show "Server did not respond. Try again."client/tests/test_merge_path_flows_sprint37.gd(whole file)CLAUDE.md(Gauntlet live / MessagePack replay / TestHarness mock) — scene-level UI flow tests. Tier model should be updated to name this tier explicitly ("scene-flow tests"). Tests couple to private fields (_waiting_for_catalog,_selected_bookmark_id,_loading_screen,_new_game_btn). UI refactor renames → all 4 tests break simultaneously. Consider a minimal public API surface tests can read.client/tests/test_merge_path_flows_sprint37.gd:30-36before_test()reaches intoSimBridge._last_snapshot,SimBridge._outbound_buffer,MetaStack._stack(private fields). Encapsulate in test-only helpers likeSimBridge.reset_for_test()rather than per-test-file reach-ins.client/scripts/protocol/protocol.gdPROTOCOL_VERSIONgone, version check removed,versionfield dropped from returned dict. Forward-compatible: snapshots with/withoutversion: 23decode identically. No change.client/tests/test_p0_regressions.gd:235-305test_bookmark_catalog_not_lost_on_snapshot_overwrite) and anti-over-carry guard (test_bookmark_catalog_not_carried_forward_after_consumption). Right shape for a carry-forward invariant — repeat for future one-shot fields.client/ui/dialogue_box.gd:625-632.replace("]", "[rb]")is sound (chained replaces corrupt earlier substitutions). Comment explains the "why" — right shape for a sharp-edge fix.Summary of blocking issues
Before this PR can merge:
journal_panel.gdandEntityRendererconstants coverage (T2) OR document why no tests are needed.tscnfails loudlyOther items (T1 signal residue, T4 timeout fallback, T5/T6 test coupling, Hoshe nits) are worth addressing before merge but could ride in a follow-up with rationale.
Review-fix pass (commit
60733738)Thanks for the thorough review. Addressed below.
Merged origin/main
Branch was behind 9 commits (D-189 source-canonical pipeline etc.). Merged
origin/mainbefore the fix commit so the PR reflects current main state.H1 — 0/0/0 runner claim: resolved
The PR body's "by inspection" note was from the prior session that couldn't run
make test-clientat all because.godot/imported/was stale — the runner returned{"total":0,"passed":0,"failed":0}with no way to trigger discovery. Today's investigation:make build-clientregenerates imports;make test-clientthen returns real counts. Commitbc310a3c's "2428/2488 passing" came from a real runner invocation against that rebuilt state.No ticket needed — the issue was "rebuild imports first", not a runner bug.
Today's run after all review-fix changes: 2428/2488 passing, 60 pre-existing failures unrelated to sprint 37 (test_dialogue_sprint20 #558 signal wiring, test_input_roundtrip integration-without-server, etc.). All sprint-37 test files are green.
H2 / top-of-review — merge ordering: agree, client-first
Per Tyre's top-of-review analysis, this PR should merge before server #137. Reasoning: main's current client has
PROTOCOL_VERSION: 23with a strict-reject guard. If server merges first, any pre-existing sessions or anyone on stale main rejects every new-server snapshot until this PR also lands — broken window. Client-first: the new client tolerates both old and new server, no broken window.The briefing's
#874 → #875text was wrong in light of main's old-client state. Acknowledged — flagging for whoever does the actual merge: this PR first, then server #137.Blocking code fixes (commit
60733738)_load_main_menu/_load_char_createnowassert_that(packed).is_not_null()instead ofpush_warning + return. Missing .tscn is now a red test, not a silent green.handshake_complete(protocol_version: int)signal had no listeners. Dropped the int parameter and the literal-0 emit. No API compat concern.test_new_game_catalog_snapshot_resolves_loading_statenow assertsSimBridge.state == CONNECTEDterminus alongside the loading-flag clear. Guarantees full flow completion.test_protocol_bridge.gd:4file-level comment refreshed; drops reference to removed protocol-version-check tests.test_p0_regressions.gd:46_make_snapshot_byteshelper comment refreshed andversion: 23dropped from fixture dict.test_merge_path_flows_sprint37.gd_make_catalog_snapshotdropsversion: 23from fixture (D-192, not required).Follow-up tickets filed (non-blocking)
SimBridge.reset_for_test,MetaStack.reset_for_test) + minimal public API on scenes so UI refactors don't break all four flow tests simultaneously.H3 remaining coverage tickets
#879 (fog), #880 (journal), #881 (minimap) cover three of the eight #870 deletions. #889 (this pass) covers sprite_integration. The remaining four:
test_load_game_save_selection_sets_pending_load_path). No dedicated ticket needed.Unchecked smoke box
The last test plan box — manual
make gameNew Game flow — remains unchecked from the team worktree. It needs an X display session; covered in automated form bytest_new_game_catalog_snapshot_resolves_loading_statewhich exercises the same code path end-to-end. If a live manual smoke is required before merge, that needs to happen in a desktop session outside this worktree.Review: sprint-37/client → main (PR #135) — Round 2
Reviewers: Hoshe (code quality & tests) + Tyre (architecture).
Verdict: CHANGES REQUESTED
Blockers are documentation hygiene only — no code changes needed. Three PR-description edits + one ticket update close the round.
Hoshe — Code Quality & Tests: REQUEST_CHANGES
All nits fixed. Coverage tickets for #870 deletions all filed and verified (#879 fog, #880 journal, #881 minimap, #889 sprite_integration). Two real blockers on test-evidence hygiene.
Round-1 status
60733738reportsmake test-client — 2428/2488 passing, but the PR body's test plan section still reads "0/0/0 runner output is a known infra problem, not caused by these changes; individual test files verified by inspection" with all six checkboxes unchecked. The comment update is better than nothing; the body edit is missing. Plus a 60 vs 22 failure-count gap — commit namestest_dialogue_sprint20 #558 signalsandtest_input_roundtrip integration-sans-serveras examples of the 60 "pre-existing" failures. Ticket #871 (sprint-36 pre-existing triage) covers 22 failures. The 60 > 22 delta means 38 failures are currently untracked per memoryfeedback_broken_tests_not_preexisting_shield.md. Either update #871 to document the full 60 (with rationale for the extra 38 — e.g. "newly visible after sprint-37 import rebuild"), or file a companion ticket.journal_panel.gd601-line surface:player_knowledge, scene lifecycle, UIStrings,_state_color), #881 minimap, #889 EntityRenderer sprite constants.debug_overlayacceptably exempt (dev-only, disabled in export builds).entanglement/sprint30/session_managercovered by umbrella #871 though the "incidentally covered by merge-path tests" claim forsession_manageris weak — none of the merge-path tests assertSessionManagerAPI contracts (ID format, uniqueness,resume_game()). Rephrase the exemption to "coverage gap tracked under #871."test_new_game_catalog_snapshot_resolves_loading_stateassertsSimBridge.state == SimBridge.ConnectionState.CONNECTEDwith explicit failure messagetest_protocol_bridge.gd:4stale headertest_p0_regressions.gd:46stale helper comment_make_snapshot_bytesdict no longer containsversionkey_make_catalog_snapshotover-specifiedversion: 23Merge-path smoke gate (skill 0b-i)
PR body still shows all six boxes unchecked, including the three merge-path items:
test_merge_path_flows_sprint37.gdrunner coverageAutomated coverage exists for all three (
test_new_game_catalog_snapshot_resolves_loading_stateasserts the full chain; protocol smoke is covered by forward-compat test). Update the PR body to reflect this — either tick the automated boxes with a note "covered by automated test" or keep them unchecked and explicitly say what's being deferred to a manual smoke by whom.Tyre — Architecture: REQUEST_CHANGES
T1, T3 code fixes are clean. Deferrals #889, #890, #891 are substantive (not placeholders). B1 retracted — see below.
Round-1 status
signal handshake_complete(protocol_version: int)residueclient/#870coverage loss (journal + EntityRenderer)_load_main_menu/_load_char_createnow useassert_that(packed).override_failure_message(...).is_not_null(). Missing.tscnfails loudlymain_menu.gd:72-74poll loop, proposes ~10s timer + retry UX)SimBridge.reset_for_test(),MetaStack.reset_for_test(), minimal public API)469377camerges main). Client-first ordering acknowledged in a PR comment but not in the PR body — see B3Round-1 B1 retracted
I flagged "journal_panel coverage companion ticket missing" as a round-2 blocker. Incorrect: #880 was filed 2026-04-21 and covers the full
journal_panel.gdtest surface (player_knowledge snapshot parsing, scene lifecycle, entry rendering, UIStrings confidence/source keys,_state_colorfor Contradicted/Stale/Active). I missed the ticket in my scan — Hoshe found it. Retracted, no fix needed on B1.Round-2 blockers (documentation only)
60733738reports 2428/2488 passing, PR body still reads "0/0/0 runner output is a known infra problem" with all six boxes unchecked. Mutually inconsistent. Either the runner works (update the prose, tick the automated boxes) or it doesn't (the commit message overstates).Merge order: this PR (client) before server PR #137 — main currently pairs an old client with the D-192 server.Summary
All round-1 code concerns resolved. Three remaining blockers are all documentation:
No code changes needed. Fastest close yet if picked up promptly.
Round-2 blockers addressed (documentation only)
make test-clientresult (2428/2488 passing, 23 failing test cases tracked under #871). Automated boxes ticked; the manualmake gameNew Game smoke is the only one still unchecked, with an explicit defer rationale (needs X display, stronger automated coverage exists).## 🚨 Merge ordersection to the PR body so anyone opening the PR seesthis PR (client) must merge BEFORE server PR #137without needing to find the review thread.60733738's message was assertion-level (gdUnit4 JSONfailed); the 22-23 in #871 is test-case level. Same 13 suites, same tests, different counting mode. #871 updated with the current 23-case enumeration, the delta vs sprint-36 (no new suites, no upward regressions — several suites improved, test_bug_report_ring_buffer and test_game_state dropped out entirely thanks to sprint-37 fixes), and an umbrella note for the three sprint-37 #870 deletions that don't have dedicated revive tickets (entanglement, sprint30, session_manager).No code changes this pass. Ready for re-review.
Review: sprint-37/client → main (PR #135) — Round 3
Reviewers: Hoshe (code quality & tests) + Tyre (architecture) — direct verification, no code changes this round.
Verdict: APPROVED
Three round-2 blockers resolved without new commits — all were documentation / ticket edits.
Round-2 status
2428/2488 passing, 23 failing test cases (60 assertion-level failures). All sprint-37 test files green.5 of 6 boxes now ticked; themake gamemanual smoke box is explicitly deferred with rationale: no X display from team worktree, and the automatedtest_new_game_catalog_snapshot_resolves_loading_stateasserts the full CONNECTED-state terminus — stronger than a one-shot manual checkRound-1/2 summary
Merge reminder
Client first, then server. Main currently pairs an old client (
PROTOCOL_VERSION: 23strict reject) with the D-192-aware server on origin/main. Client merges → new client tolerates both old and new server during the rollout. Server merges second → all clients now accept no-version snapshots.Summary
Three-round review arc on PR #135:
Fastest round-3 close of sprint 37. Ready to merge.
Pull request closed