* fix(issue-6): prevent A* diagonal corner-cutting through blocked cells
The A* neighbor loop previously checked only whether the destination cell
was free. For diagonal moves this allows agents to clip through the corner
of a blocked cell — the two orthogonal neighbours (e.g. N and E for a NE
move) were never validated.
Fix: after confirming the diagonal destination is free, additionally check
both orthogonal intermediary cells. If either is blocked, the diagonal
expansion is skipped and the agent must route around the obstacle.
Adds three unit tests covering:
- a path that would clip a single corner (rejected after fix)
- a path through open space (diagonals still used freely)
- a path around a multi-cell wall segment (no cells in the wall visited)
* chore: remove unused imports from diagonal corner test (lint cleanup)
* test(navigation): add expanded diagonal corner-cutting tests (issue #6)
Additional tests for astar diagonal corner-cutting prevention:
- All 4 diagonal directions (NE, NW, SE, SW): block orthogonal neighbour,
verify path avoids the blocked cell in each direction
- Both orthogonal sides blocked: verify no diagonal move is taken from start
- L-shaped wall: verify agent navigates around entire L without clipping any segment
- Dense grid stress test: maze-like layout verifying valid path found and no
waypoint lands on a blocked cell
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>
* Fix WS auth: wire accessGate.allowUpgrade via verifyClient
The allowWs callback was never actually calling accessGate.allowUpgrade
during the WS handshake - the ws library passes (info) not (req), and
verifyClient must be set on the WebSocketServer constructor options.
Fix: pass verifyClient to WebSocketServer constructor and wrap
allowUpgrade to extract info.req.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix TypeScript error and add gym release directive support
Add "release" value to OfficeGymDirective type for symmetry with
OfficeQaDirective ("qa_lab" | "release"). Previously OfficeGymDirective
was only "gym" with no release state, making the "!== 'release'"
check in eventTriggers.ts dead code that TypeScript flagged as an
unintentional comparison.
Changes:
- deskDirectives.ts: add "release" to OfficeGymDirective type
- deskDirectives.ts: add gym release patterns to skill and command
directive resolvers (e.g. "leave the gym", "done with skills")
- eventTriggers.ts: change !== "release" to === "gym" for clarity
and consistency with reduceOfficeGymHoldState pattern
This fixes: https://github.com/iamlukethedev/Claw3D/issues/15
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>