Skip to content

fix(pathfinder): crash on grid top/bottom-edge starts and goals#94

Merged
Maudfer merged 3 commits into
mainfrom
fix/pathfinder-grid-edge
Jul 12, 2026
Merged

fix(pathfinder): crash on grid top/bottom-edge starts and goals#94
Maudfer merged 3 commits into
mainfrom
fix/pathfinder-grid-edge

Conversation

@Maudfer

@Maudfer Maudfer commented Jul 12, 2026

Copy link
Copy Markdown
Owner

The bug

PathFinder.getValidNeighbors (src/app/game/PathFinder.ts) indexed the tile
matrix before any bounds check:

// TODO: handle grid edges
const neighborTile = matrix[neighbor.row]![neighbor.col];

Field.matrix is a { [row]: { [col]: Tile } } map, so for a neighbor off the
top edge (row === -1) or bottom edge (row === rows), matrix[row] is
undefined and indexing it throws TypeError: Cannot read properties of undefined (reading '<col>'). Out-of-bounds columns were already handled
gracefully (the col index just returns undefined → filtered), but rows
crashed. Any pathfinding request whose start or goal sits on the grid's
top/bottom edge (a very reachable state — roads/buildings can be placed against
the map border) crashed the pather.

The fix

Move the field.isValidPosition(row, col) bounds check ahead of the matrix
index so an out-of-bounds row (or col) is filtered before indexing — exactly how
out-of-bounds columns were already tolerated. The trailing isValid term in the
return is now guaranteed true, so it's dropped, and the stale
// TODO: handle grid edges is removed.

Tests

New test/pathFinder.test.ts (there was no pre-existing pathfinder test on this
branch) exercises real behavior — a valid collapsed path is returned, not merely
"doesn't throw":

  • top edge: start on row 0 (NORTH neighbor is row -1) → routes across two footprints.
  • bottom edge: start on the last row (SOUTH neighbor is off-grid) → routes across two footprints.
  • every-neighbor-off-an-edge: a single road filling a 3×3 grid, corner start → returns the single collapsed step.

Revert-dance (proves the test guards the fix)

  • Fix + test in place → npx jest test/pathFinder.test.ts green (3/3).
  • git stash push -- src/app/game/PathFinder.ts (buggy source restored) → all 3 fail with TypeError: Cannot read properties of undefined (reading '0') at the old matrix[neighbor.row]! index line.
  • git stash pop (fix restored) → green again.

Observed the fail→pass transition, so the test genuinely catches the regression.

Gates

  • npx tsc --noEmit -p tsconfig.json — clean (exit 0).
  • npx jest (full suite) — 73 suites / 647 tests green.
  • Coverage on src/app/game/PathFinder.ts85.71% stmts / 75% branch / 100% funcs (≥ 80% stmt bar).

Notes on task vs. repo state

The task described a src/app/game/agents/ + test/agents/ layout with
--selectProjects agents, a per-module coverage project, an eslint gate, and a
pre-written pinned test. None of that exists on this branch: PathFinder.ts is
flat at src/app/game/, tests are a single flat test/ suite, there is no
eslint config/dependency in the repo, and no pathfinder test existed. I adapted
to the actual repo — fixed the real bug at the real path, added a new flat test,
and ran the gates that exist here (tsc / jest / coverage). Test imports use
../src/... to match all 73 existing test files (the repo convention; no test
uses path aliases).

🤖 Generated with Claude Code

…he matrix

getValidNeighbors indexed `matrix[neighbor.row]![neighbor.col]` before any
bounds check, so probing the NORTH neighbor of a start on row 0 (or the SOUTH
neighbor on the last row) hit `matrix[-1]` (undefined) and threw a TypeError
instead of being filtered out like out-of-bounds columns already were. Any
pathfinding request whose start or goal sat on the grid's top/bottom edge
crashed.

Move the `isValidPosition` bounds check ahead of the matrix index (guarding row
AND col) and drop the now-redundant trailing `isValid` term. Removes the stale
`// TODO: handle grid edges`.

Adds test/pathFinder.test.ts covering top-edge, bottom-edge, and
every-neighbor-off-an-edge starts. Revert-dance verified: with the fix reverted
all three tests fail with the TypeError at the old index line; restored, green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Maudfer Maudfer self-assigned this Jul 12, 2026
@Maudfer Maudfer added the bug Something isn't working label Jul 12, 2026
Maudfer and others added 2 commits July 11, 2026 22:56
…g merge

Merging main (PR #93 game/test reorg) moved PathFinder to game/agents/ and
brought in the canonical test/agents/pathFinder.test.ts, whose pinned test
asserted the OLD crash ("a start on the grid top edge crashes..."). The grid-edge
fix (carried onto agents/PathFinder.ts by rename detection) makes that no longer
throw, so update the pinned test to assert the fixed behavior — no throw AND a
valid path found — and add a matching bottom-edge case (both use unpadded
matrices, mirroring a real Field's top/bottom edge).

Remove the now-redundant flat test/pathFinder.test.ts (added before the reorg
was on this branch); its cases are folded into the canonical agents test, and
the flat path no longer matches any Jest project's testMatch.

Revert-dance (agents module): with the pre-fix index-before-bounds-check
restored, exactly the top- and bottom-edge tests fail with "Cannot read
properties of undefined"; with the fix, all 97 agents tests pass.
agents/PathFinder.ts coverage 89.6% stmts (module 93.3%), above the 80% gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Maudfer Maudfer merged commit d6c7c31 into main Jul 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant