From aed65255cc65016157e9ccf232008082475e3715 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 13 Sep 2026 17:59:48 +0200 Subject: [PATCH] Follow CultLib Cut 3: opening hydrates, PullOnOpen is gone CultLib's CultCacheMessagePack.Create and OpenAsync now always read the store, and CultCacheOpenOptions.PullOnOpen no longer exists. - CultCachePatchDocumentStore.WriteDefaultAsync and AquaSynthDaemonService.WriteReceiptAsync write single-document files. They open (which hydrates), remove every record other than the one they write, upsert, and flush; the flush replaces the file atomically. Before this, Create never pulled, so their PullOnOpen = false was already a no-op. - IpaTrialResults and SpeechDistributedTraining passed File.Exists-style PullOnOpen values; hydrating a missing store is empty, so the option goes. - AquaSynthDaemonServiceTests drops PullOnOpen = true. Globals: nothing in CultLib invents a [CultGlobal] record any more. AquaSynth never relied on that: its three global types are positional records with no parameterless constructor, which the old invention skipped, and every one is written explicitly and read back by explicit key or GetAll. Co-Authored-By: Claude Opus 5 --- src/AquaSynth.Core/CultCachePatchDocument.cs | 9 ++++++--- src/AquaSynth.Core/IpaTrialResults.cs | 13 ++++++------- src/AquaSynth.Core/SpeechDistributedTraining.cs | 7 ++----- src/AquaSynth.Faust/AquaSynthDaemonService.cs | 8 +++++++- .../AquaSynthDaemonServiceTests.cs | 3 +-- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/AquaSynth.Core/CultCachePatchDocument.cs b/src/AquaSynth.Core/CultCachePatchDocument.cs index 6f910f7..9e73596 100644 --- a/src/AquaSynth.Core/CultCachePatchDocument.cs +++ b/src/AquaSynth.Core/CultCachePatchDocument.cs @@ -87,10 +87,13 @@ public static class CultCachePatchDocumentStore { public static async Task WriteDefaultAsync(string filePath) { - using var cache = CultCacheMessagePack.Create(filePath, new CultCacheOpenOptions + // Opening hydrates; this file holds exactly the default document, so everything else goes before the write. + using var cache = CultCacheMessagePack.Create(filePath); + foreach (var stale in cache.AllStoredDocuments.Where(stored => stored.Key.Value != CultCachePatchDocumentCatalog.Key).ToArray()) { - PullOnOpen = false - }); + cache.Remove(stale.Key); + } + await cache.UpsertAsync( CultCachePatchDocumentCatalog.CreateDefault(), new CultRecordHandle(new CultRecordKey(CultCachePatchDocumentCatalog.Key))) diff --git a/src/AquaSynth.Core/IpaTrialResults.cs b/src/AquaSynth.Core/IpaTrialResults.cs index ae427fa..7957cc9 100644 --- a/src/AquaSynth.Core/IpaTrialResults.cs +++ b/src/AquaSynth.Core/IpaTrialResults.cs @@ -115,7 +115,7 @@ public static class IpaTrialResultCultCacheStore return []; } - using var cache = await OpenTrialStoreAsync(filePath, pullOnOpen: true).ConfigureAwait(false); + using var cache = await OpenTrialStoreAsync(filePath).ConfigureAwait(false); return cache.GetAll() .OrderBy(result => result.TrialId, StringComparer.Ordinal) .ToArray(); @@ -128,7 +128,7 @@ public static class IpaTrialResultCultCacheStore return []; } - using var cache = await OpenTrialStoreAsync(filePath, pullOnOpen: true).ConfigureAwait(false); + using var cache = await OpenTrialStoreAsync(filePath).ConfigureAwait(false); return cache.GetAll() .OrderBy(document => document.EvidenceId, StringComparer.Ordinal) .ToArray(); @@ -141,7 +141,7 @@ public static class IpaTrialResultCultCacheStore return []; } - using var cache = await OpenTrialStoreAsync(filePath, pullOnOpen: true).ConfigureAwait(false); + using var cache = await OpenTrialStoreAsync(filePath).ConfigureAwait(false); return cache.GetAll() .OrderBy(document => document.DistillationId, StringComparer.Ordinal) .ToArray(); @@ -154,7 +154,7 @@ public static class IpaTrialResultCultCacheStore return []; } - using var cache = await OpenTrialStoreAsync(filePath, pullOnOpen: true).ConfigureAwait(false); + using var cache = await OpenTrialStoreAsync(filePath).ConfigureAwait(false); return cache.GetAll() .OrderBy(document => document.KnowledgeId, StringComparer.Ordinal) .ToArray(); @@ -172,7 +172,7 @@ public static class IpaTrialResultCultCacheStore Directory.CreateDirectory(directory); } - using var cache = await OpenTrialStoreAsync(filePath, pullOnOpen: StoreExists(filePath)).ConfigureAwait(false); + using var cache = await OpenTrialStoreAsync(filePath).ConfigureAwait(false); foreach (var document in documents) { await cache.UpsertAsync(document, new CultRecordHandle(new CultRecordKey(key(document)))).ConfigureAwait(false); @@ -181,12 +181,11 @@ public static class IpaTrialResultCultCacheStore await cache.FlushAsync().ConfigureAwait(false); } - private static Task OpenTrialStoreAsync(string filePath, bool pullOnOpen) => + private static Task OpenTrialStoreAsync(string filePath) => CultCacheMessagePack.OpenAsync( filePath, new CultCacheOpenOptions { - PullOnOpen = pullOnOpen, UseDirectoryStore = true }); diff --git a/src/AquaSynth.Core/SpeechDistributedTraining.cs b/src/AquaSynth.Core/SpeechDistributedTraining.cs index 0b47776..ec994aa 100644 --- a/src/AquaSynth.Core/SpeechDistributedTraining.cs +++ b/src/AquaSynth.Core/SpeechDistributedTraining.cs @@ -257,11 +257,8 @@ public static class SpeechDistributedTrainingCultCacheStore return cache.GetAll().OrderBy(orderKey, StringComparer.Ordinal).ToArray(); } - private static async Task OpenForMutationAsync(string filePath) - { - var options = new CultCacheOpenOptions { PullOnOpen = File.Exists(filePath) }; - return await CultCacheMessagePack.OpenAsync(filePath, options).ConfigureAwait(false); - } + private static Task OpenForMutationAsync(string filePath) => + CultCacheMessagePack.OpenAsync(filePath); } public static class SpeechDistributedTrainingCoordinator diff --git a/src/AquaSynth.Faust/AquaSynthDaemonService.cs b/src/AquaSynth.Faust/AquaSynthDaemonService.cs index 6cda512..28ae62d 100644 --- a/src/AquaSynth.Faust/AquaSynthDaemonService.cs +++ b/src/AquaSynth.Faust/AquaSynthDaemonService.cs @@ -920,8 +920,14 @@ public sealed class AquaSynthDaemonService : IDisposable { var filePath = Path.Combine(options.StoreRoot, family, $"{SafeFileName(id)}.cc"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); - using var cache = CultCacheMessagePack.Create(filePath, new CultCacheOpenOptions { PullOnOpen = false }); + // Opening hydrates; a receipt file holds exactly one document, so everything else goes before the write. + using var cache = CultCacheMessagePack.Create(filePath); var key = global ? new CultRecordKey("global") : new CultRecordKey(id); + foreach (var stale in cache.AllStoredDocuments.Where(stored => !stored.Key.Equals(key)).ToArray()) + { + cache.Remove(stale.Key); + } + await cache.UpsertAsync(document, new CultRecordHandle(key)).ConfigureAwait(false); await cache.FlushAsync().ConfigureAwait(false); } diff --git a/tests/AquaSynth.Dsl.Tests/AquaSynthDaemonServiceTests.cs b/tests/AquaSynth.Dsl.Tests/AquaSynthDaemonServiceTests.cs index 7ccb69e..129491f 100644 --- a/tests/AquaSynth.Dsl.Tests/AquaSynthDaemonServiceTests.cs +++ b/tests/AquaSynth.Dsl.Tests/AquaSynthDaemonServiceTests.cs @@ -210,8 +210,7 @@ public sealed class AquaSynthDaemonServiceTests private static async Task ReadLiveSessionStateAsync(string storeRoot, string sessionId) { using var cache = await CultCacheMessagePack.OpenAsync( - Path.Combine(storeRoot, "live-sessions", $"{sessionId}.cc"), - new CultCacheOpenOptions { PullOnOpen = true }).ConfigureAwait(false); + Path.Combine(storeRoot, "live-sessions", $"{sessionId}.cc")).ConfigureAwait(false); return Assert.Single(cache.GetAll()); } }