NEO-48: revert WhenWritingNull on skill-progression grant API
Keep omit-null reasonCode only on new perk-state responses; restoring the existing grant endpoint wire format (reasonCode: null on success).pull/83/head
parent
12e52bccc9
commit
00c5937872
|
|
@ -8,6 +8,7 @@ docs {
|
|||
NEO-38: single skill XP grant + allowlist + level-up metadata; see server README.
|
||||
NEO-40: same contract; server adds comment-only telemetry hook markers (no request/response change).
|
||||
NEO-47: on level-up, server re-evaluates mastery perk unlocks internally (no JSON change until NEO-48 perk-state HTTP).
|
||||
Success responses include reasonCode: null (stable since NEO-38); perk-state POST omits reasonCode on success instead.
|
||||
E2.M2 tracking row in docs/decomposition/modules/documentation_and_implementation_alignment.md lists NEO-40 landed with plan + manual QA links.
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ tests {
|
|||
const body = res.getBody();
|
||||
expect(body.schemaVersion).to.equal(1);
|
||||
expect(body.granted).to.equal(true);
|
||||
expect(body.reasonCode).to.equal(null);
|
||||
expect(body.progression).to.be.an("object");
|
||||
expect(body.progression.schemaVersion).to.equal(1);
|
||||
expect(body.progression.playerId).to.equal("dev-local-1");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using NeonSprawl.Server.Game.Skills;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -120,6 +121,26 @@ public sealed class SkillProgressionGrantApiTests
|
|||
Assert.Equal(SkillProgressionSnapshotApi.ReasonInvalidAmount, envelope.ReasonCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostSkillProgression_ShouldSerializeReasonCodeNull_OnSuccess()
|
||||
{
|
||||
// Arrange
|
||||
await using var factory = new InMemoryWebApplicationFactory();
|
||||
var client = factory.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.PostAsJsonAsync(
|
||||
"/game/players/dev-local-1/skill-progression",
|
||||
ValidGrant("salvage", amount: 10));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
Assert.True(doc.RootElement.TryGetProperty("reasonCode", out var reasonCode));
|
||||
Assert.Equal(JsonValueKind.Null, reasonCode.ValueKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PostSkillProgression_ShouldApplyGrant_AndGetMatches_WhenTrainerAllowedForRefine()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ public sealed class SkillProgressionGrantResponse
|
|||
|
||||
/// <remarks>Set when <see cref="Granted"/> is <c>false</c>; stable snake_case values (see README).</remarks>
|
||||
[JsonPropertyName("reasonCode")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? ReasonCode { get; init; }
|
||||
|
||||
[JsonPropertyName("progression")]
|
||||
|
|
|
|||
Loading…
Reference in New Issue