feat(trade): atomic two-phase commit lock for player item trading - #137
feat(trade): atomic two-phase commit lock for player item trading#137Rodrigoue9 wants to merge 7 commits into
Conversation
| export function isTradeReadyForSettlement(session: TradeSession, timeoutMs: number = 30000): boolean { | ||
| if (!session.senderAccepted || !session.receiverAccepted) return false; | ||
| const now = Date.now(); | ||
| if (now - session.lockedAt > timeoutMs) return false; // expired | ||
| return true; |
There was a problem hiding this comment.
⚠️ Edge Case: Expired trade indistinguishable from not-yet-accepted
isTradeReadyForSettlement returns false both when a party hasn't accepted (line 16) and when an accepted trade has timed out (line 18). A caller using only this boolean cannot tell "still pending" from "expired and must be rolled back", so an accepted-but-expired escrow can be silently left in limbo — items stay locked and are never released, the exact inventory-duplication/timeout scenario the PR aims to prevent. Return a discriminated status (e.g. 'ready' | 'pending' | 'expired') or expose a separate isExpired() so callers can trigger cancellation.
Was this helpful? React with 👍 / 👎
| export function isTradeReadyForSettlement(session: TradeSession, timeoutMs: number = 30000): boolean { | ||
| if (!session.senderAccepted || !session.receiverAccepted) return false; | ||
| const now = Date.now(); | ||
| if (now - session.lockedAt > timeoutMs) return false; // expired | ||
| return true; |
There was a problem hiding this comment.
💡 Quality: Trade lock provides no atomicity or locking, only a check
Despite the PR's "atomic two-phase commit lock" framing, isTradeReadyForSettlement is a stateless pure predicate: it never acquires a lock, mutates session state, or guarantees the settlement that follows is atomic with respect to concurrent reads. Two concurrent callers can both observe true and both proceed to settle, which does not prevent the described race/duplication. The actual locking/commit step needs to be implemented (e.g. transactional inventory transfer with a single-owner lock flag) rather than relying on this readiness check.
Was this helpful? React with 👍 / 👎
| for (const off of offsets) { | ||
| const targetX = Math.min(Math.max(startX + off.dx, mapBounds.minX), mapBounds.maxX); | ||
| const targetY = Math.min(Math.max(startY + off.dy, mapBounds.minY), mapBounds.maxY); | ||
| waypoints.push({ x: targetX, y: targetY, step: step++ }); | ||
| } |
There was a problem hiding this comment.
💡 Edge Case: Patrol waypoints collapse to duplicates near map edges
generatePatrolWaypoints clamps each offset target to mapBounds (lines 40-41). When the NPC starts on or near a boundary, multiple distinct offsets clamp to the same coordinate, producing consecutive duplicate waypoints and a degenerate patrol that stalls in a corner. Consider de-duplicating consecutive waypoints or reflecting the patrol inward when clamping would collapse points. A negative or zero radius likewise collapses all waypoints onto the start; validating radius > 0 would help.
Was this helpful? React with 👍 / 👎
Code Review
|
| Auto-apply | Compact |
|
|
Important
Your trial ends in 7 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.
Was this helpful? React with 👍 / 👎 | Gitar
Trade Settlement Engine
Ready for review! 🚀
Summary by Gitar
clan_membersbefore running dependent data migrationslayerBlendMode.tsmapNpcPlacement.tsnpcs.jsonto unblock CI and market testsThis will update automatically on new commits.