Fix character enrichment claim isolation

This commit is contained in:
Nick Beckley 2026-09-07 20:09:18 +00:00
parent 46afaff981
commit 265f2afa50
2 changed files with 56 additions and 0 deletions

View File

@ -1278,6 +1278,7 @@ static void StoryIntelligenceCharacterEnrichmentPromotesStructuredFacts()
var models = File.ReadAllText(Path.Combine(root, "Models/CharacterEnrichmentModels.cs")); var models = File.ReadAllText(Path.Combine(root, "Models/CharacterEnrichmentModels.cs"));
var service = File.ReadAllText(Path.Combine(root, "Services/CharacterEnrichmentService.cs")); var service = File.ReadAllText(Path.Combine(root, "Services/CharacterEnrichmentService.cs"));
var migration = File.ReadAllText(Path.Combine(root, "Sql/188_Phase27O_CharacterEnrichmentStructuredFacts.sql")); var migration = File.ReadAllText(Path.Combine(root, "Sql/188_Phase27O_CharacterEnrichmentStructuredFacts.sql"));
var claimIsolationMigration = File.ReadAllText(Path.Combine(root, "Sql/190_Phase27Q_CharacterEnrichmentClaimIsolation.sql"));
Assert(models.Contains("CharacterEnrichmentFactResult Sex", StringComparison.Ordinal), "Character enrichment should extract sex as an evidenced structured fact."); Assert(models.Contains("CharacterEnrichmentFactResult Sex", StringComparison.Ordinal), "Character enrichment should extract sex as an evidenced structured fact.");
Assert(service.Contains("Do not place ascertainable facts only in the summary", StringComparison.Ordinal), "Prompt should require structured facts as well as summary prose."); Assert(service.Contains("Do not place ascertainable facts only in the summary", StringComparison.Ordinal), "Prompt should require structured facts as well as summary prose.");
@ -1292,6 +1293,8 @@ static void StoryIntelligenceCharacterEnrichmentPromotesStructuredFacts()
&& migration.Contains("INNER JOIN @Results", StringComparison.Ordinal), "SQL completion should replace same-run evidence idempotently."); && migration.Contains("INNER JOIN @Results", StringComparison.Ordinal), "SQL completion should replace same-run evidence idempotently.");
Assert(migration.Contains("BEGIN TRANSACTION", StringComparison.Ordinal) Assert(migration.Contains("BEGIN TRANSACTION", StringComparison.Ordinal)
&& migration.Contains("COMMIT TRANSACTION", StringComparison.Ordinal), "Character enrichment claim and completion should be transactional."); && migration.Contains("COMMIT TRANSACTION", StringComparison.Ordinal), "Character enrichment claim and completion should be transactional.");
Assert(claimIsolationMigration.Contains("CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentRun_ClaimNext", StringComparison.Ordinal)
&& !claimIsolationMigration.Contains("READPAST", StringComparison.OrdinalIgnoreCase), "Character enrichment claim locking should avoid READPAST isolation failures.");
} }
static void CharacterDetailCanQueueSingleCharacterEnrichment() static void CharacterDetailCanQueueSingleCharacterEnrichment()

View File

@ -0,0 +1,53 @@
CREATE OR ALTER PROCEDURE dbo.CharacterEnrichmentRun_ClaimNext
@LeaseMinutes int = 90
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @RunID int;
BEGIN TRANSACTION;
SELECT TOP (1) @RunID = CharacterEnrichmentRunID
FROM dbo.CharacterEnrichmentRuns WITH (UPDLOCK, HOLDLOCK)
WHERE IsCurrent = 1
AND (
Status = N'Queued'
OR (Status = N'Running' AND StartedUtc < DATEADD(minute, -ABS(@LeaseMinutes), SYSUTCDATETIME()))
)
ORDER BY QueuedUtc, CharacterEnrichmentRunID;
IF @RunID IS NULL
BEGIN
COMMIT TRANSACTION;
SELECT TOP (0) * FROM dbo.CharacterEnrichmentRuns;
RETURN;
END;
UPDATE dbo.CharacterEnrichmentRuns
SET Status = N'Running',
StartedUtc = SYSUTCDATETIME(),
AttemptCount = AttemptCount + 1,
CurrentStage = N'Preparing character analysis',
CurrentMessage = N'Preparing character analysis...',
UpdatedUtc = SYSUTCDATETIME()
WHERE CharacterEnrichmentRunID = @RunID
AND IsCurrent = 1
AND (
Status = N'Queued'
OR (Status = N'Running' AND StartedUtc < DATEADD(minute, -ABS(@LeaseMinutes), SYSUTCDATETIME()))
);
IF @@ROWCOUNT = 0
BEGIN
COMMIT TRANSACTION;
SELECT TOP (0) * FROM dbo.CharacterEnrichmentRuns;
RETURN;
END;
SELECT * FROM dbo.CharacterEnrichmentRuns WHERE CharacterEnrichmentRunID = @RunID;
COMMIT TRANSACTION;
END;
GO