Add GameOver to EventType enum and GameOverPayload DTO.
GameRedisPublisher publishes to {prefix}:game-over stream (MAXLEN ~1000)
on game completion. NativeReflectionConfig updated for core module.
Closes NCS-102
https://knockoutwhist.youtrack.cloud/issue/NCS-102
Reviewed-on: #64
## Summary
- Implements the full tournament lifecycle (create, join, withdraw, start,
round progression, finish) as a standalone Quarkus module
- All 11 endpoints from the OpenAPI spec (`docs/tournament-openapi.yaml`) are covered
- Swiss pairing algorithm with Buchholz tiebreak and bye support
- Per-bot NDJSON event stream with targeted `gameStart` events carrying
the correct `color` field
- Game results ingested via Redis writeback stream (`GameResultStreamListener`)
## Known gaps (deferred)
- `GET /results` `nb` param defaults to 100 instead of all
- `PairingDto` exposes an internal `id` field not in the spec
- `GameExport.moves` emits PGN instead of UCI (upstream `GameWritebackEventDto`
does not carry UCI moves)
- `Pairing.white` can be `null` for bye rounds (spec has no bye concept)
## Test plan
- [x] 23 `TournamentResourceTest` integration tests (H2, mocked core client) — all pass
- [x] 5 `SwissPairingServiceTest` unit tests — all pass
- [x] Redis listener excluded in test/dev profiles; no Docker required to run tests
---------
Co-authored-by: LQ63 <lkhermann@web.de>
Co-authored-by: Lala, Shahd <Shahd.Lala@sybit.de>
Reviewed-on: #55
Replace synchronous account→core game-creation HTTP call and plain
pub/sub bot game-start events with Redis Streams using consumer groups,
XACK, retry, and a Dead Letter Queue for at-least-once delivery and
observability.
- account: GameCreationStreamClient publishes game-creation requests and
correlates responses via a per-instance consumer group (NCS-91)
- core: GameCreationStreamListener consumes requests, calls
GameCreationService, publishes response events, retries, and routes
exhausted/unparseable events to the DLQ (NCS-91, NCS-93, NCS-94)
- official-bots: bot game-start events migrated from pub/sub to Streams
with consumer group, XACK, retry, and DLQ (NCS-92)
- account EventPublisher dual-writes to the stream and legacy pub/sub
channel for backward compatibility
- all flows use the typed EventEnvelope (eventId/type/payload/timestamp/
correlationId) with DLQ error context (eventType, error, attempt)
- register new DTOs and EventEnvelope/EventType for native reflection
Closes NCS-91, NCS-92, NCS-93, NCS-94
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Janis Eccarius <eccariusjanis@gmail.com>
Reviewed-on: #62
Two bugs in move notation causing PGN import failures in LiChess:
1. Disambiguation: when two pieces of same type can reach same square,
SAN requires file/rank/full-square prefix (e.g. "Ndf3" not "Nf3").
Added disambiguate() in PgnExporter and disambiguatePiece() in
GameEngine, both querying allLegalMoves to find competing pieces.
2. Check/checkmate suffix: "+" and "#" were never appended.
PgnExporter now threads ctxAfter through moveToAlgebraic and
calls DefaultRules.isCheck/isCheckmate. GameEngine passes
PostMoveStatus to translateMoveToNotation for the same result.
Also removes dead notation code in executeMoveBody (result was never
used — not passed to MoveExecutedEvent).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Janis Eccarius <eccariusjanis@gmail.com>
Reviewed-on: #56
Track whether subscribeGame is being called and completing successfully
to diagnose empty game-writeback messages.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add lastUpdatedMs timestamp to GameCacheDto to track actual game updates instead of heartbeat time. Fix cache eviction incorrectly marking correspondence games as idle.
- Use atomic SPOP in LoadBalancer.getGamesToMove() to prevent concurrent rebalance calls from selecting same games for migration.
- Add game→instance reverse mapping (nowchess:game:$gameId:instance) to eliminate O(instances) linear scan during cache eviction.
- Fix HealthMonitor pod matching from loose contains() to reliable endsWith() to prevent matching unintended pods with similar names.
- Update FailoverService to maintain game→instance mappings when migrating games during failover.
- Update CacheEvictionManager to use game→instance mapping for O(1) lookup instead of O(n) instance scan.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>