feat(rank-progress): RankProgressResult carries TierAdvanced signal

RankProgressResult gains a TierAdvanced bool (defaulted false so the 7-arg
positional-constructor sites don't break). Set true iff the grant is a win
AND RankTier.Name resolves both pre-grant and post-grant to distinct strings —
i.e. a promotion crossed a tier boundary.

Explicitly guards on isWin so a demotion (in principle possible after a loss
below a tier floor, though the current floor rules prevent it) never fires
the achievement backward.

Three new tests: no-cross win, beginner→d cross, loss stays false.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-04 13:32:45 -04:00
parent 8e41739bde
commit e9c13ae5f4
3 changed files with 65 additions and 5 deletions

View File

@@ -4,9 +4,13 @@ using SVSim.Database.Models;
namespace SVSim.Database.Services.RankProgress;
/// <summary>
/// Wire-shape result of a single rank-battle finish grant. All fields map 1:1 to
/// <c>RankBattleFinishResponseDto</c> keys the client reads via GetValueOrDefault
/// in Wizard/RankBattleFinishTask.cs:57-63.
/// Wire-shape result of a single rank-battle finish grant. The wire-mapped fields
/// (<see cref="Rank"/>, <see cref="AfterBattlePoint"/>, <see cref="AfterMasterPoint"/>,
/// <see cref="BattlePoint"/>, <see cref="MasterPoint"/>, <see cref="IsMasterRank"/>,
/// <see cref="IsGrandMasterRank"/>) map 1:1 to <c>RankBattleFinishResponseDto</c>
/// keys the client reads via GetValueOrDefault in Wizard/RankBattleFinishTask.cs:57-63.
/// <see cref="TierAdvanced"/> is a controller-side signal for the rank_achieved mission
/// emit and is not serialized to the wire.
/// </summary>
/// <param name="Rank">rank_id post-grant (1..29).</param>
/// <param name="AfterBattlePoint">Point post-grant (accumulated).</param>
@@ -15,6 +19,10 @@ namespace SVSim.Database.Services.RankProgress;
/// <param name="MasterPoint">Signed MasterPoint delta.</param>
/// <param name="IsMasterRank">True iff Rank == 25.</param>
/// <param name="IsGrandMasterRank">True iff Rank &gt;= 26.</param>
/// <param name="TierAdvanced">
/// True iff this grant crossed the viewer into a higher <see cref="RankTier"/> bucket
/// than they held pre-grant. Callsites gate rank_achieved mission emits on this flag.
/// </param>
public sealed record RankProgressResult(
int Rank,
int AfterBattlePoint,
@@ -22,7 +30,8 @@ public sealed record RankProgressResult(
int BattlePoint,
int MasterPoint,
bool IsMasterRank,
bool IsGrandMasterRank);
bool IsGrandMasterRank,
bool TierAdvanced = false);
public interface IRankProgressService
{