fix(cv-qa): preserve reviewed mapping order and verify merge journeys
This commit is contained in:
@@ -185,7 +185,7 @@ public sealed partial class ProfileCvController
|
||||
if (mappings.Count > 25 || mappings.Any(m => m is null)) return BadRequest("Invalid or excessive record mappings.");
|
||||
// Preserve hashes for old requests and already-applied historical reviews.
|
||||
var hashBytes = mappings.Count == 0 ? JsonSerializer.SerializeToUtf8Bytes(new { request.ExpectedVersion, Decisions = request.Decisions.OrderBy(d => d.Id, StringComparer.Ordinal) })
|
||||
: JsonSerializer.SerializeToUtf8Bytes(new { request.ExpectedVersion, Decisions = request.Decisions.OrderBy(d => d.Id, StringComparer.Ordinal), Mappings = mappings.OrderBy(m => m.ClientId, StringComparer.Ordinal) });
|
||||
: JsonSerializer.SerializeToUtf8Bytes(new { request.ExpectedVersion, Decisions = request.Decisions.OrderBy(d => d.Id, StringComparer.Ordinal), Mappings = mappings });
|
||||
var hash = Convert.ToHexString(SHA256.HashData(hashBytes));
|
||||
try
|
||||
{
|
||||
@@ -197,7 +197,15 @@ public sealed partial class ProfileCvController
|
||||
if (run.Status == "applied")
|
||||
{
|
||||
var prior = JsonSerializer.Deserialize<AppliedReview>(run.ReviewJson ?? "null");
|
||||
return prior?.Hash == hash ? Ok(new { runId = id, status = "applied", revision = prior.Revision, structuredCv = prior.StructuredCv }) : Conflict("This import has already been applied with different decisions.");
|
||||
var sameMappings = mappings.Count == 0 || JsonSerializer.Serialize(prior?.Mappings) == JsonSerializer.Serialize(mappings);
|
||||
var identical = prior?.Hash == hash && sameMappings;
|
||||
// Old mapping receipts sorted IDs; accept their exact original order only.
|
||||
if (!identical && prior is not null && mappings.Count > 0 && sameMappings)
|
||||
{
|
||||
var legacyHash = Convert.ToHexString(SHA256.HashData(JsonSerializer.SerializeToUtf8Bytes(new { request.ExpectedVersion, Decisions = request.Decisions.OrderBy(d => d.Id, StringComparer.Ordinal), Mappings = mappings.OrderBy(m => m.ClientId, StringComparer.Ordinal) })));
|
||||
identical = prior.Hash == legacyHash;
|
||||
}
|
||||
return identical ? Ok(new { runId = id, status = "applied", revision = prior!.Revision, structuredCv = prior.StructuredCv }) : Conflict("This import has already been applied with different decisions.");
|
||||
}
|
||||
if (run.Status != "pending_review" || string.IsNullOrWhiteSpace(run.StructuredProfileJson)) return Conflict("This import is not awaiting review.");
|
||||
var snapshot = await _careerProfileService.LoadSnapshotAsync(user.Id, HttpContext.RequestAborted);
|
||||
|
||||
@@ -77,7 +77,7 @@ public static class CvImportMapping
|
||||
var result = Node(current);
|
||||
var metadata = result["metadata"]!["fields"]!.AsObject();
|
||||
var scalarWrites = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var mapping in mappings.OrderBy(m => m.ClientId, StringComparer.Ordinal))
|
||||
foreach (var mapping in mappings)
|
||||
{
|
||||
var catalog = Categories.Single(c => c.Category == mapping.Category);
|
||||
if (mapping.Fields.Count == 0) throw new ArgumentException("A record mapping must contain reviewed fields.");
|
||||
|
||||
Reference in New Issue
Block a user