Skip to content

feat(combat): browser grid combat-with-movement + grid-extent fix (#10)#1173

Merged
100yenadmin merged 3 commits into
mainfrom
feat/browser-combat-movement
Jun 26, 2026
Merged

feat(combat): browser grid combat-with-movement + grid-extent fix (#10)#1173
100yenadmin merged 3 commits into
mainfrom
feat/browser-combat-movement

Conversation

@100yenadmin

Copy link
Copy Markdown
Member

Summary

Lane A of the S2 plan — OBJECTIVE-1's functional core (turn-based combat WITH MOVEMENT), on the reliable web path. Builds on the merged keystone (#1171): the player-turn arbiter already resolves move_to_cell/on-turn attack over /move; this adds the grid board that consumes it + a board-extent fix so tokens never fall off-board.

  • viewer/server.py _scene_grid_block (Epic 9: AI Companion #10): the rendered board EXTENT now follows the combat tactical grid (combat.grid_width/grid_height) when combat declares one, so a token placed on a >16×10 grid isn't clipped off-board (a 20×20 fight previously reported a 16×10 board). Additive — no explicit combat grid ⇒ today's 16×10 default / scene_grid extent. +5 unit tests.
  • viewer/openworlds/screen-combat.jsx: render a real cols×rows tactical board when the engine sends authoritative cells (grid.mode==="grid") — the slot the existing CombatMap comment explicitly reserved. Click an empty cell → POST move_to_cell; click a foe → POST attack (echo turnToken, gate on can_act); apply the refreshed surface the grid /move lane returns. The engine stays the SOLE WRITER — the board only posts intents; zones render unchanged for non-grid surfaces.

Validation

End-to-end in the browser preview against a live 14×10 combat-on-tavern demo:

  • click an empty cell → the hero walks there (engine-resolved, movement-budget-validated);
  • click the adjacent goblin → attack resolves ("Rolan misses Goblin Cutter"), turn advances, the enemy auto-runs, the round advances.
  • curl cross-check: surface reports the correct 14×10 grid; move_to_cell moves the token.
  • Full viewer suite 786 passed, Tier-0 GREEN.
  • /move sole-writer path unchanged (this adds a client + a presentation-only extent read, not a write path).

Licensing / CLA

Source-available WorldOS; additive change, no new deps.

Lane A of the S2 plan — OBJECTIVE-1's functional core, on the reliable web path:

- viewer/server.py `_scene_grid_block` (#10): the board EXTENT now follows the combat tactical grid
  (combat.grid_width/grid_height) when combat declares one, so a token never lands off-board (a 20x20
  fight previously reported a 16x10 board). Additive (no combat grid ⇒ today's 16x10 default). 5 unit tests.
- viewer/openworlds/screen-combat.jsx: render a real cols×rows tactical board when the engine sends
  authoritative cells (grid.mode=="grid") — the slot the existing comment reserved. Click an empty cell →
  POST move_to_cell; click a foe → POST attack (echo turnToken, gate can_act); apply the refreshed surface
  the grid lane returns. The engine stays the SOLE WRITER — the board only posts intents.

Verified end-to-end in the browser preview against a live 14x10 combat-on-tavern demo: click an empty cell
walks the hero (engine-resolved, movement-budget-validated); click the adjacent goblin resolves an attack,
advances the turn, the enemy auto-runs, the round advances. Full viewer suite 786 passed, Tier-0 GREEN.
The /move sole-writer is unchanged (this adds a client, not a write path).
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e8006677-b6d5-47dc-a81c-c596b55a9fc8

📥 Commits

Reviewing files that changed from the base of the PR and between 1cc1f93 and 84e8873.

📒 Files selected for processing (1)
  • viewer/openworlds/screen-combat.jsx
📜 Recent review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: test
  • GitHub Check: Analyze (python)
  • GitHub Check: viewer-tests
  • GitHub Check: test
  • GitHub Check: viewer-tests
⚠️ CI failures not shown inline (2)

GitHub Actions: LLM Quality Gate (advisory) / quality-gate: feat(combat): browser grid combat-with-movement + grid-extent fix (#10)

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "[selfcheck] bash -n on the duo runner + scorer"�[0m
 �[36;1mbash -n qa/run_duo.sh�[0m
 �[36;1mbash -n qa/score.sh�[0m
 �[36;1mtest -x qa/run_duo.sh�[0m
 �[36;1mtest -x qa/score.sh�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] regression detector imports + answers --help (pure reader, no DB write)"�[0m
 �[36;1muv run --directory servers/engine python "${GITHUB_WORKSPACE}/qa/detect_regression.py" --help >/dev/null�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] scorer guard path emits a hashed artifact into a TEMP dir (gateway-free)"�[0m
 �[36;1mtmp="$(mktemp -d)"�[0m
 �[36;1mprintf '# transcript\n' > "$tmp/t.md"�[0m
 �[36;1mprintf '{}\n'           > "$tmp/state.json"�[0m
 �[36;1mWORLDOS_SCORE_GUARD_ONLY=1 bash qa/score.sh \�[0m
 �[36;1m  "$tmp/t.md" "$tmp/state.json" qa/rubric.md qa/score_schema.json "$tmp/out.json" 0.01�[0m
 �[36;1mtest -s "$tmp/out.json"�[0m
 �[36;1mrm -rf "$tmp"�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] jq present (scorecard tool)"�[0m
 �[36;1mcommand -v jq >/dev/null || { echo "::error title=LLM Quality Gate::jq missing on runner"; exit 1; }�[0m

GitHub Actions: LLM Quality Gate (advisory) / 0_quality-gate.txt: feat(combat): browser grid combat-with-movement + grid-extent fix (#10)

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "[selfcheck] bash -n on the duo runner + scorer"�[0m
 �[36;1mbash -n qa/run_duo.sh�[0m
 �[36;1mbash -n qa/score.sh�[0m
 �[36;1mtest -x qa/run_duo.sh�[0m
 �[36;1mtest -x qa/score.sh�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] regression detector imports + answers --help (pure reader, no DB write)"�[0m
 �[36;1muv run --directory servers/engine python "${GITHUB_WORKSPACE}/qa/detect_regression.py" --help >/dev/null�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] scorer guard path emits a hashed artifact into a TEMP dir (gateway-free)"�[0m
 �[36;1mtmp="$(mktemp -d)"�[0m
 �[36;1mprintf '# transcript\n' > "$tmp/t.md"�[0m
 �[36;1mprintf '{}\n'           > "$tmp/state.json"�[0m
 �[36;1mWORLDOS_SCORE_GUARD_ONLY=1 bash qa/score.sh \�[0m
 �[36;1m  "$tmp/t.md" "$tmp/state.json" qa/rubric.md qa/score_schema.json "$tmp/out.json" 0.01�[0m
 �[36;1mtest -s "$tmp/out.json"�[0m
 �[36;1mrm -rf "$tmp"�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] jq present (scorecard tool)"�[0m
 �[36;1mcommand -v jq >/dev/null || { echo "::error title=LLM Quality Gate::jq missing on runner"; exit 1; }�[0m
🔇 Additional comments (1)
viewer/openworlds/screen-combat.jsx (1)

498-511: LGTM!


📝 Walkthrough

Priority: P1

Adds browser-based grid combat with movement/attacks executed during a turn, and fixes viewer rendering so the tactical board size and terrain rules match the engine.

  • Viewer/server extent fix: viewer/server.py::_scene_grid_block keeps the legacy 16×10 default when no valid combat grid is present, but when snapshot["combat"].grid_width/grid_height are provided it overrides cols/rows to the tactical grid while preserving any location scene_grid metadata (sceneId, cells, cellDefault) for tint/walkability.
  • Combat grid rendering: viewer/openworlds/screen-combat.jsx renders a real cols × rows tactical grid when grid.mode === "grid" (otherwise it falls back to the prior non-grid board).
  • Grid click behavior (turn-gated): clicking an empty walkable cell posts move_to_cell {x,y}; clicking a foe token posts attack {target_id}; ally-token clicks select. Actions are gated by canAct.
  • Walkability correctness: per-cell grid.cells overrides now take precedence for both walkable: true and walkable: false over grid.cellDefault.walkable (isWalkable records explicit overrides and falls back to cellDefault only when no override exists).
  • Intent posting & surface refresh: postCombatIntent posts POST /move with turn_token (and campaign), uses a synchronous busyRef guard to prevent double submissions, appends a local “player-intent” log row on success, and applies refreshed state via payload.combat when returned (otherwise it calls loadSurface()).
  • Tests: viewer/tests/test_move_intents.py adds SceneGridBlockExtentTests covering default behavior, combat-extent overrides (including >16×10), malformed degradation, mode preservation, and precedence/metadata-survival when both scene_grid and combat grid are present.

Walkthrough

Adds tactical grid combat in the viewer: combat intents now post move or attack actions through /move, the board can render grid cells and tokens, and server-side board extents now follow combat dimensions. Tests cover the updated extent selection.

Changes

Grid combat flow

Layer / File(s) Summary
Board extents from combat grid
viewer/server.py, viewer/tests/test_move_intents.py
_scene_grid_block keeps scene-grid fields when present and uses combat grid_width/grid_height for cols/rows; tests cover the default, malformed, oversized, and mixed scene-grid cases.
Move and attack intents
viewer/openworlds/screen-combat.jsx
postCombatIntent posts /move with turn_token, move_to_cell, or attack, records the local intent, updates the combat surface from payload.combat or reloads it, and the screen passes the new callbacks and canAct into CombatMap.
Grid board rendering
viewer/openworlds/screen-combat.jsx
CombatGridBoard renders tactical cells, token markers, and cell click actions, and CombatMap returns it when grid mode and dimensions are valid.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Confidence: 91%

Possibly related PRs

Suggested labels

graphics, cap:c1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: browser grid combat with movement plus a grid-extent fix.
Description check ✅ Passed The description covers summary and validation, but the CLA section is missing the required checkbox items from the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/browser-combat-movement

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the graphics Graphics & game-types roadmap initiative label Jun 26, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@viewer/openworlds/screen-combat.jsx`:
- Around line 490-528: The CombatGridBoard render logic currently treats every
empty square as a valid move target, ignoring the engine-provided terrain data.
Update CombatGridBoard to derive each cell’s walkability from grid.cells and
grid.cellDefault, then use that per-cell state in the cells map so blocked tiles
are styled differently and do not trigger onCellMove. Keep the existing
token/attack behavior intact, but only allow movement clicks on walkable cells.
- Around line 523-533: The tactical board cell handling in screen-combat.jsx is
blocking selection behind the action gate and only supports mouse clicks, unlike
the zone renderer. Update the cell interaction logic around the
clickable/onClick block so onSelect can still work even when canAct is false,
and add proper keyboard accessibility for actionable cells (button semantics or
tabIndex with Enter/Space handlers plus focus styling) so tokens remain
inspectable and usable for non-mouse users.

In `@viewer/tests/test_move_intents.py`:
- Around line 242-264: The current tests for _scene_grid_block() only cover
combat data in isolation, so add a mixed-source regression case that includes
both locations[current_location_id].scene_grid and combat in the input. In that
test, verify that combat.grid_width/grid_height still control the returned
cols/rows, while scene-grid metadata such as sceneId, cells, and cellDefault is
preserved and not overwritten by scene_grid.grid.cols/rows. Use
_scene_grid_block() and the existing scene_grid/combat merge behavior to lock in
the intended precedence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 26128e0e-be9c-4006-a201-b0207840f3b7

📥 Commits

Reviewing files that changed from the base of the PR and between cbba241 and 01f69d2.

📒 Files selected for processing (3)
  • viewer/openworlds/screen-combat.jsx
  • viewer/server.py
  • viewer/tests/test_move_intents.py
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: test
  • GitHub Check: viewer-tests
  • GitHub Check: Analyze (python)
  • GitHub Check: test
  • GitHub Check: viewer-tests
⚠️ CI failures not shown inline (2)

GitHub Actions: LLM Quality Gate (advisory) / quality-gate: feat(combat): browser grid combat-with-movement + grid-extent fix (#10)

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "[selfcheck] bash -n on the duo runner + scorer"�[0m
 �[36;1mbash -n qa/run_duo.sh�[0m
 �[36;1mbash -n qa/score.sh�[0m
 �[36;1mtest -x qa/run_duo.sh�[0m
 �[36;1mtest -x qa/score.sh�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] regression detector imports + answers --help (pure reader, no DB write)"�[0m
 �[36;1muv run --directory servers/engine python "${GITHUB_WORKSPACE}/qa/detect_regression.py" --help >/dev/null�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] scorer guard path emits a hashed artifact into a TEMP dir (gateway-free)"�[0m
 �[36;1mtmp="$(mktemp -d)"�[0m
 �[36;1mprintf '# transcript\n' > "$tmp/t.md"�[0m
 �[36;1mprintf '{}\n'           > "$tmp/state.json"�[0m
 �[36;1mWORLDOS_SCORE_GUARD_ONLY=1 bash qa/score.sh \�[0m
 �[36;1m  "$tmp/t.md" "$tmp/state.json" qa/rubric.md qa/score_schema.json "$tmp/out.json" 0.01�[0m
 �[36;1mtest -s "$tmp/out.json"�[0m
 �[36;1mrm -rf "$tmp"�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] jq present (scorecard tool)"�[0m
 �[36;1mcommand -v jq >/dev/null || { echo "::error title=LLM Quality Gate::jq missing on runner"; exit 1; }�[0m

GitHub Actions: LLM Quality Gate (advisory) / 0_quality-gate.txt: feat(combat): browser grid combat-with-movement + grid-extent fix (#10)

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "[selfcheck] bash -n on the duo runner + scorer"�[0m
 �[36;1mbash -n qa/run_duo.sh�[0m
 �[36;1mbash -n qa/score.sh�[0m
 �[36;1mtest -x qa/run_duo.sh�[0m
 �[36;1mtest -x qa/score.sh�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] regression detector imports + answers --help (pure reader, no DB write)"�[0m
 �[36;1muv run --directory servers/engine python "${GITHUB_WORKSPACE}/qa/detect_regression.py" --help >/dev/null�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] scorer guard path emits a hashed artifact into a TEMP dir (gateway-free)"�[0m
 �[36;1mtmp="$(mktemp -d)"�[0m
 �[36;1mprintf '# transcript\n' > "$tmp/t.md"�[0m
 �[36;1mprintf '{}\n'           > "$tmp/state.json"�[0m
 �[36;1mWORLDOS_SCORE_GUARD_ONLY=1 bash qa/score.sh \�[0m
 �[36;1m  "$tmp/t.md" "$tmp/state.json" qa/rubric.md qa/score_schema.json "$tmp/out.json" 0.01�[0m
 �[36;1mtest -s "$tmp/out.json"�[0m
 �[36;1mrm -rf "$tmp"�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] jq present (scorecard tool)"�[0m
 �[36;1mcommand -v jq >/dev/null || { echo "::error title=LLM Quality Gate::jq missing on runner"; exit 1; }�[0m
🧰 Additional context used
🪛 ast-grep (0.44.0)
viewer/openworlds/screen-combat.jsx

[warning] 183-183: Avoid using the initial state variable in setState
Context: setBusyAction(label)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 534-534: A list component should have a key to prevent re-rendering
Context: <GridCellToken t={t} selected={selected === t.id} isCurrent={t.id === curId} />
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(list-component-needs-key)

Comment thread viewer/openworlds/screen-combat.jsx Outdated
Comment thread viewer/openworlds/screen-combat.jsx Outdated
Comment thread viewer/tests/test_move_intents.py
… mixed-source test (#1173)

- screen-combat.jsx: derive per-cell walkability from grid.cells/cellDefault (the engine wall/prop map);
  blocked cells are styled + NOT move targets (no more illegal move_to_cell into a wall relying on /move
  rejection to correct the UI).
- screen-combat.jsx: token SELECTION now bypasses the can_act gate (inspect tokens on any turn, like the
  zone renderer); actionable cells get button semantics (role/tabIndex + Enter/Space handler + focus ring).
- test_move_intents.py: add a mixed scene_grid+combat case locking the precedence — combat owns cols/rows
  while the scene_grid sceneId/cells/cellDefault survive.

(ast-grep nits refuted: line 183 setBusyAction(label) — `label` is a param, not the initial state var;
GridCellToken "needs key" — the key is on the parent cell div, GridCellToken is a single conditional child.)
Re-verified in the browser preview (board renders, no console errors); 24 move-intents tests pass.
@100yenadmin 100yenadmin enabled auto-merge (squash) June 26, 2026 17:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@viewer/openworlds/screen-combat.jsx`:
- Around line 500-505: The grid walkability logic in the combat screen only
tracks blocked cells, so explicit per-cell walkable:true overrides are ignored
when cellDefault.walkable is false. Update the walkability lookup around the
blocked/defaultWalkable/isWalkable logic to record both blocked and explicit
walkable cells from grid.cells, and have isWalkable(x, y) return true for
explicit walkable overrides before falling back to the grid default.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 83e8b804-89ee-45e4-9a32-1ca333e37b62

📥 Commits

Reviewing files that changed from the base of the PR and between 01f69d2 and 1cc1f93.

📒 Files selected for processing (2)
  • viewer/openworlds/screen-combat.jsx
  • viewer/tests/test_move_intents.py
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: test
  • GitHub Check: viewer-tests
  • GitHub Check: Analyze (python)
  • GitHub Check: viewer-tests
  • GitHub Check: test
⚠️ CI failures not shown inline (2)

GitHub Actions: LLM Quality Gate (advisory) / 0_quality-gate.txt: feat(combat): browser grid combat-with-movement + grid-extent fix (#10)

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "[selfcheck] bash -n on the duo runner + scorer"�[0m
 �[36;1mbash -n qa/run_duo.sh�[0m
 �[36;1mbash -n qa/score.sh�[0m
 �[36;1mtest -x qa/run_duo.sh�[0m
 �[36;1mtest -x qa/score.sh�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] regression detector imports + answers --help (pure reader, no DB write)"�[0m
 �[36;1muv run --directory servers/engine python "${GITHUB_WORKSPACE}/qa/detect_regression.py" --help >/dev/null�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] scorer guard path emits a hashed artifact into a TEMP dir (gateway-free)"�[0m
 �[36;1mtmp="$(mktemp -d)"�[0m
 �[36;1mprintf '# transcript\n' > "$tmp/t.md"�[0m
 �[36;1mprintf '{}\n'           > "$tmp/state.json"�[0m
 �[36;1mWORLDOS_SCORE_GUARD_ONLY=1 bash qa/score.sh \�[0m
 �[36;1m  "$tmp/t.md" "$tmp/state.json" qa/rubric.md qa/score_schema.json "$tmp/out.json" 0.01�[0m
 �[36;1mtest -s "$tmp/out.json"�[0m
 �[36;1mrm -rf "$tmp"�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] jq present (scorecard tool)"�[0m
 �[36;1mcommand -v jq >/dev/null || { echo "::error title=LLM Quality Gate::jq missing on runner"; exit 1; }�[0m

GitHub Actions: LLM Quality Gate (advisory) / quality-gate: feat(combat): browser grid combat-with-movement + grid-extent fix (#10)

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "[selfcheck] bash -n on the duo runner + scorer"�[0m
 �[36;1mbash -n qa/run_duo.sh�[0m
 �[36;1mbash -n qa/score.sh�[0m
 �[36;1mtest -x qa/run_duo.sh�[0m
 �[36;1mtest -x qa/score.sh�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] regression detector imports + answers --help (pure reader, no DB write)"�[0m
 �[36;1muv run --directory servers/engine python "${GITHUB_WORKSPACE}/qa/detect_regression.py" --help >/dev/null�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] scorer guard path emits a hashed artifact into a TEMP dir (gateway-free)"�[0m
 �[36;1mtmp="$(mktemp -d)"�[0m
 �[36;1mprintf '# transcript\n' > "$tmp/t.md"�[0m
 �[36;1mprintf '{}\n'           > "$tmp/state.json"�[0m
 �[36;1mWORLDOS_SCORE_GUARD_ONLY=1 bash qa/score.sh \�[0m
 �[36;1m  "$tmp/t.md" "$tmp/state.json" qa/rubric.md qa/score_schema.json "$tmp/out.json" 0.01�[0m
 �[36;1mtest -s "$tmp/out.json"�[0m
 �[36;1mrm -rf "$tmp"�[0m
 �[36;1m�[0m
 �[36;1mecho "[selfcheck] jq present (scorecard tool)"�[0m
 �[36;1mcommand -v jq >/dev/null || { echo "::error title=LLM Quality Gate::jq missing on runner"; exit 1; }�[0m
🔇 Additional comments (1)
viewer/tests/test_move_intents.py (1)

237-285: LGTM!

Comment thread viewer/openworlds/screen-combat.jsx Outdated
…oard (#1173)

CodeRabbit round-2: the terrain map only recorded BLOCKED cells, so a scene with
cellDefault.walkable=false + explicit walkable:true floors would wrongly treat those floors as
non-walkable. Now record the full per-cell override (true OR false); isWalkable returns the
override when present, else falls back to cellDefault. No current scene_grid emitter sets
cellDefault.walkable=false, but the contract allows it. JSX transpiles clean (vendored babel).
@coderabbitai coderabbitai Bot added the cap:c1 Capability C1 — positioning model (theater/zone/grid) label Jun 26, 2026
@100yenadmin 100yenadmin merged commit c43ac1f into main Jun 26, 2026
31 checks passed
@100yenadmin 100yenadmin deleted the feat/browser-combat-movement branch June 26, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cap:c1 Capability C1 — positioning model (theater/zone/grid) graphics Graphics & game-types roadmap initiative

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant