feat: add support for score data and implement match correction mechanism - #155
Merged
Dejmenek merged 29 commits intoSep 16, 2026
Conversation
Added `Play_ReturnsNegativeScoreError_WhenScoreIsNegative` to ensure the `Play` mutation returns an error when negative scores are provided. This test verifies error codes, messages, and extensions, and ensures the match remains unmodified in the database. Added `Play_ReturnsWinnerScoreMismatchError_WhenWinnerScoreIsNotHigher` to validate that the `Play` mutation enforces the rule that the winner's score must be higher. This test also verifies error codes, messages, and extensions, and ensures the match remains unmodified.
Tests include: - Validation for non-negative scores for both players. - Validation for winner having a higher score than the opponent. - Edge cases such as tied scores and negative scores.
Added a new constant `RoundDataChanged` to the `BracketErrorCodes` class to represent a new error code for concurrent round data changes. Introduced a new method `RoundDataChangedConcurrently` in the `BracketErrors` class to generate an error object with a descriptive message, error code, and `BracketId` as context.
Updated the `ValidateAllMatchesCompleted` method in the `BracketMutationValidations` class to check if any match's `Status` is not equal to `MatchStatus.Played` instead of checking for a `null` `WinnerId`. This improves the accuracy of the validation by relying on the `Status` property, which provides a more reliable indicator of match completion.
Added a `Status` property to the `Match` class to track match status. Replaced the `Version` property with `RowVersion`, annotated with `[IsProjected(true)]`. Introduced a new `MatchStatus` enum with values `Scheduled`, `Played`, and `NeedsReplay` to represent different match states.
Added a new `MatchCorrectionAudit` entity to track audit logs for match corrections. Updated `ApplicationDbContext` to include a `DbSet` for `MatchCorrectionAudits` and configured its relationships, primary key, and indexes in `OnModelCreating`. The `MatchCorrectionAudit` entity includes properties for tracking match corrections, such as previous and new statuses, player IDs, scores, and the user who performed the correction. Relationships to `Match` and `ApplicationUser` entities were defined with `DeleteBehavior.Restrict`.
Enhanced error handling by adding new error codes to the `MatchErrorCodes` class, including `MatchNotYetPlayed`, `MatchNeedsReplay`, `InvalidVersionToken`, `MatchVersionConflict`, and `MatchCorrectionFailed`. Added corresponding error methods to the `MatchErrors` class to generate detailed error messages for these scenarios, improving clarity and robustness in match operation error reporting.
Added logic to determine if a match requires a replay by checking its status and storing the result in the `isReplay` variable. Introduced variables to preserve the previous state of the match, including status, winner, player IDs, and scores. Updated the match's properties (`WinnerId`, `Player1Score`, `Player2Score`, and `Status`) to reflect the new state, explicitly setting the status to `MatchStatus.Played`. Implemented replay handling by invoking `MatchCorrectionService.ApplyCorrectionAsync` when a replay is detected, passing the previous match state and other relevant parameters. Ensured that corrections are applied before saving changes to the database asynchronously.
`MatchCascadePositionCalculator`: - Added `GetDownstreamMatchId` to calculate downstream match IDs in a tournament bracket. `MatchCorrectionService`: - Added `ApplyCorrectionAsync` to handle match corrections, including audit logging and downstream propagation. - Added `RecordIdempotentDuplicateAsync` to log duplicate correction requests. - Added `PropagateAsync` to propagate corrections downstream, updating match participants, status, and winner as needed. - Added `BuildAuditRow` to create detailed audit logs for corrections.
Added the `CorrectMatchResult` method in `MatchMutations` to allow authorized users to correct match results. This includes extensive validation checks for match existence, user ownership, tournament status, and score validity. Enhanced error handling ensures proper reporting of concurrency conflicts and database update failures. Introduced the `GetVersion` resolver in `MatchResolvers` to encode and return the `RowVersion` of a match for version tracking. Updated `ValidateMatchNotPlayed` in `MatchValidations` to use `MatchStatus` for determining if a match has been played. Added new validation methods: `ValidateMatchNotScheduled` and `ValidateMatchNotNeedsReplay`.
Implemented comprehensive test cases to cover: - Score-only corrections without cascading changes. - Winner changes with and without downstream matches. - Cascade handling for downstream matches. - Error handling for invalid inputs (e.g., non-existent matches, unauthorized users, negative scores, stale versions, etc.). - Concurrency handling for identical requests. - Audit logging with correlation IDs and chains. - Champion self-healing after invalidated final matches.
The test ensures: - Replay operation completes successfully without errors. - Match status updates to `Played` and winner remains unchanged. - Downstream matches are updated correctly. - An additional audit row is written to `MatchCorrectionAudits`.
Added `Status` and `Version` properties to the `MatchNode` class to store additional metadata about matches. Introduced the `CorrectMatchResultResponse` and `CorrectMatchResultResult` classes to handle responses for correcting match results. Added the `CorrectMatchResult` GraphQL mutation to enable correcting match results programmatically. Also added the `GetMatchesForRoundWithStatusAndVersion` query to retrieve matches for a specific round, including the new `Status` and `Version` fields for better data handling and visibility.
Implemented the following unit tests for the `GetDownstreamMatchId` method: - Verifies correct downstream match ID for even positions. - Verifies correct downstream match ID for odd positions. - Ensures `null` is returned when the next round is not generated. - Ensures `null` is returned for invalid match IDs. - Ensures `null` is returned for trailing byes not yet generated.
- Added `EncodeThenTryDecode_RoundTripsToTheOriginalBytes` to verify encoding and decoding round-trip functionality. - Added `TryDecode_WhenInputIsNull_ReturnsFalse` to ensure null input handling. - Added `TryDecode_WhenInputIsEmpty_ReturnsFalse` to ensure empty string handling. - Added `TryDecode_WhenInputIsMalformedBase64_ReturnsFalse` to validate malformed Base64 input handling.
…em needs replay - Updated `ValidateAllMatchesCompleted_WhenSomeMatchesHaveNoWinner_ReturnsError` to use `MatchStatus.Played` and `MatchStatus.Scheduled`. - Updated `ValidateAllMatchesCompleted_WhenAllMatchesHaveWinner_ReturnsNull` to use `MatchStatus.Played`. - Added `ValidateAllMatchesCompleted_WhenAMatchNeedsReplay_ReturnsError` to test replay-needed matches and validate error handling.
Introduced new test methods: - `ValidateMatchNotPlayed` now tests for `NeedsReplay`. - `ValidateMatchNotScheduled` tests for `Scheduled`, `Played`, and `NeedsReplay`. - `ValidateMatchNotNeedsReplay` tests for `NeedsReplay`, `Scheduled`, and `Played`.
Dejmenek
deleted the
feat/102-no-match-score-data-and-no-way-to-correct-a-mistaken-result
branch
September 16, 2026 09:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces a robust mechanism for correcting match results, ensuring data integrity, cascade propagation, and concurrency handling in tournament brackets. Adds explicit match statuses, audit logging, and validation enhancements. Exposes match score data.
Changes
Match.cs: AddedMatchStatusenum,Player1Score,Player2Score, andRowVersionfor concurrency control.MatchMutations.cs: AddedCorrectMatchResultmutation and enhancedPlaymutation with score handling and concurrency guards.MatchCorrectionService.cs: Implemented cascade propagation for downstream match updates and audit logging.DatabaseSeeder.cs: Updated to populateMatchStatusfor all seeded matches.MatchValidations.cs: Added validations for negative scores, winner mismatches, and invalid statuses.