From c8563e533f7c68eb132952d6954c5acfa2efe01f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 28 Oct 2026 06:39:26 +0100 Subject: [PATCH] Single-file judge: the removals need not travel as checks (a removal has no upsert); pin the flatten and retype refusal texts Co-Authored-By: Claude Opus 5.5 --- src/GameCult.Caching/CultCache.cs | 2 +- tests/GameCult.Caching.Tests/RetypeEvictionTests.cs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index 797540b0..2508f77c 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -4872,7 +4872,7 @@ namespace GameCult.Caching durable, _staged.Concat(upserts.Select(staged => staged.Record.Key)).Concat(removals).Concat(checks).Concat(StagedChecks), upserts, - checks.Concat(removals)); + checks); // A key the write also names as a removal or check (the request's, or one the cache removed here since its last flush) is a // retype's removal half: it is judged by the removal rule, and the record staged there then lands. A refused key's durable diff --git a/tests/GameCult.Caching.Tests/RetypeEvictionTests.cs b/tests/GameCult.Caching.Tests/RetypeEvictionTests.cs index fd38541d..ad1c4072 100644 --- a/tests/GameCult.Caching.Tests/RetypeEvictionTests.cs +++ b/tests/GameCult.Caching.Tests/RetypeEvictionTests.cs @@ -251,11 +251,12 @@ namespace GameCult.Caching.Tests batch.UpsertVariant(K3, baseA, new[] { cache.Override(nameof(EvA.Name), "v3") }); }); - Assert.Throws(() => cache.Commit(batch => + var flatten = Assert.Throws(() => cache.Commit(batch => { batch.Remove(K3); batch.Flatten(K3); - })); + }))!; + Assert.That(flatten.Message, Does.Contain("Flatten(k3)").And.Contain("not a variant")); Assert.That(cache.GetStored(K3)!.Variant, Is.Not.Null, "the refused batch changed nothing"); Assert.That(cache.Remove(K3), Is.True); Assert.Throws(() => cache.FlattenAsync(K3).GetAwaiter().GetResult()); @@ -305,11 +306,13 @@ namespace GameCult.Caching.Tests using var cache = Open(NewPath(kind), kind, AB); PutB(cache, K2); - Assert.Throws(() => cache.Commit(batch => + var refused = Assert.Throws(() => cache.Commit(batch => { batch.Upsert(typeof(EvA), new EvA { Name = "k2", Value = 1 }, K2); batch.Upsert(typeof(EvA), new EvA { Name = "k2", Value = 2 }, K2); - })); + }))!; + if (kind == "storeless") + Assert.That(refused.Message, Does.Contain("would retype the key").And.Contain("Remove the record first, in the same batch or an earlier commit, then add the other type's.")); Assert.That(cache.GetStored(K2)!.Descriptor.DocumentType, Is.EqualTo(typeof(EvB))); }