From cd67c0df21592351bb298d3848793d0e1f3e47c6 Mon Sep 17 00:00:00 2001 From: cesnimda Date: Mon, 26 Oct 2026 15:57:06 +0100 Subject: [PATCH] test(cv-import): verify canonical revision and preserved profile on MariaDB --- .../CvImportReviewedPersistenceTests.cs | 25 +++++++++++++++++++ docs/cv-import/BACKEND.md | 6 +++++ docs/cv-import/TODO.md | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/JobTrackerApi.MariaDb.Tests/CvImportReviewedPersistenceTests.cs b/JobTrackerApi.MariaDb.Tests/CvImportReviewedPersistenceTests.cs index 69d111c..31606ad 100644 --- a/JobTrackerApi.MariaDb.Tests/CvImportReviewedPersistenceTests.cs +++ b/JobTrackerApi.MariaDb.Tests/CvImportReviewedPersistenceTests.cs @@ -17,6 +17,31 @@ namespace JobTrackerApi.MariaDb.Tests; public class CvImportReviewedPersistenceTests { + private readonly Xunit.Abstractions.ITestOutputHelper _output; + public CvImportReviewedPersistenceTests(Xunit.Abstractions.ITestOutputHelper output) => _output = output; + + [Fact] + public async Task Existing_profile_fields_survive_and_import_metadata_uses_the_canonical_revision() + { + await using var database = await MariaDbDatabase.CreateAsync(); + await using var db = database.Context(); + var run = await Seed(db); + await new CareerProfileService(db).SaveVersionAsync(Owner, new() { Summary = { "Preserve my summary" }, Contact = new() { GitHub = "https://github.com/existing" }, OtherSections = { new() { Title = "Private", Items = { "Preserve my custom fact" } } } }, "manual", 0, default); + (await db.Users.SingleAsync()).CurrentCvProfileVersion = 99; + await db.SaveChangesAsync(); + var controller = Controller(db); + var clock = System.Diagnostics.Stopwatch.StartNew(); + Assert.IsType(await controller.ApplyReviewed(run.Id, new(1, new[] { new CvImportDecision("skills.0", "use") }))); + clock.Stop(); + _output.WriteLine("ReviewedImportApplyMs={0:F3}; provider=MariaDB12.2.2; includes=validation,merge,transaction,Identity_projection", clock.Elapsed.TotalMilliseconds); + await using var verify = database.Context(); + var snapshot = await new CareerProfileService(verify).LoadSnapshotAsync(Owner, default); + Assert.Equal(2, snapshot.Revision); + Assert.Equal(2, snapshot.Profile.Metadata.ProfileVersion); + Assert.Equal("Preserve my summary", Assert.Single(snapshot.Profile.Summary)); + Assert.Equal("https://github.com/existing", snapshot.Profile.Contact.GitHub); + Assert.Equal("Preserve my custom fact", Assert.Single(Assert.Single(snapshot.Profile.OtherSections).Items)); + } private const string Owner = "rd21-owner"; private static ProfileCvController Controller(JobTrackerContext db, bool identitySucceeds = true) { diff --git a/docs/cv-import/BACKEND.md b/docs/cv-import/BACKEND.md index 80bc0a0..b3d86ec 100644 --- a/docs/cv-import/BACKEND.md +++ b/docs/cv-import/BACKEND.md @@ -43,3 +43,9 @@ The new hosted retention sweep runs on startup and hourly. New import source fil - `retention-green-01`: 50 focused cases PASS. `link-merge-red` reproduced unrelated-link replacement; `review-safe-green-01` passed 51 focused cases after correction. Focused runs overlap full regression and each other. They must never be added together. Final source-frozen regression/provider acceptance is still a separate checkpoint. + +## Provider and review addendum + +`provider-review-04` reproduced a canonical/projection revision discrepancy: legacy Identity counter 99 caused imported metadata 100 while the canonical revision was 2. Apply now derives both from the canonical snapshot. `provider-review-05` did not run tests because its nested-shell environment assignment failed; it is not a provider result. `provider-review-06` passed **70/70**, zero skips, actual MariaDB 12.2.2, cleanup exit 0. This includes preservation of unrelated existing summary/contact/custom facts and canonical revision metadata. The successful review endpoint acknowledgement follows the committed transaction. + +Lease checks now protect initial promotion, final publication and queue status synchronization. A superseded worker cannot reset a recovered pending review. All open pending reviews remain accessible beyond the latest-ten history slice. Grounded profile serialization avoids legacy heuristic enrichment. Field provenance carries the original artifact/run/SHA identities through merges and later client saves. diff --git a/docs/cv-import/TODO.md b/docs/cv-import/TODO.md index c9409c3..d576731 100644 --- a/docs/cv-import/TODO.md +++ b/docs/cv-import/TODO.md @@ -5,7 +5,7 @@ - [x] CV-IMPORT-02: grounded structured interpretation and disabled local AI qualification seam. - [x] CV-IMPORT-03: genuine progress, lease/cancellation recovery and bounded retention; full final freeze remains separate. - [x] CV-IMPORT-04: review/corrections/conflicts/source UI; final integrated regression tracked separately. -- [ ] CV-IMPORT-05: revisioned transactional Career Profile persistence. +- [x] CV-IMPORT-05: revisioned transactional Career Profile persistence; actual MariaDB 70/70 and cleanup passed. - [ ] CV-IMPORT-06: accuracy/security/resilience qualification. - [ ] CV-IMPORT-07: full regression, acceptance and CV-QA-01 handoff.