SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceBookPipeline_TryCompleteSceneAnalysis @BookID int, @UserID int AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; DECLARE @Now datetime2(7) = SYSUTCDATETIME(); DECLARE @ImportSessionID int; DECLARE @ProjectID int; DECLARE @LastRunID int; DECLARE @LastRunCreatedUtc datetime2(7); DECLARE @RunCount int = 0; DECLARE @CompletedRunCount int = 0; DECLARE @FailedRunCount int = 0; DECLARE @ActiveRunCount int = 0; DECLARE @TotalExpectedScenes int = 0; DECLARE @CompletedScenes int = 0; DECLARE @FailedScenes int = 0; DECLARE @CompletedNow bit = 0; BEGIN TRANSACTION; SELECT @ImportSessionID = pipeline.StoryIntelligenceBookPipelineID, @ProjectID = pipeline.ProjectID, @LastRunID = pipeline.LastRunID FROM dbo.StoryIntelligenceBookPipelines pipeline WITH (UPDLOCK, HOLDLOCK) INNER JOIN dbo.ProjectUserAccess access ON access.ProjectID = pipeline.ProjectID AND access.UserID = @UserID AND access.IsActive = 1 INNER JOIN dbo.Books book ON book.BookID = pipeline.BookID AND book.IsArchived = 0 INNER JOIN dbo.Projects project ON project.ProjectID = pipeline.ProjectID AND project.IsArchived = 0 WHERE pipeline.BookID = @BookID; IF @ImportSessionID IS NULL BEGIN ROLLBACK TRANSACTION; RETURN; END; SELECT @LastRunCreatedUtc = CreatedUtc FROM dbo.StoryIntelligenceRuns WHERE StoryIntelligenceRunID = @LastRunID AND BookID = @BookID AND UserID = @UserID; IF @LastRunCreatedUtc IS NULL BEGIN SELECT TOP (1) @LastRunID = StoryIntelligenceRunID, @LastRunCreatedUtc = CreatedUtc FROM dbo.StoryIntelligenceRuns WHERE BookID = @BookID AND UserID = @UserID AND ProjectID = @ProjectID ORDER BY CreatedUtc DESC, StoryIntelligenceRunID DESC; END; ;WITH ScopedRuns AS ( SELECT * FROM dbo.StoryIntelligenceRuns WHERE BookID = @BookID AND UserID = @UserID AND ProjectID = @ProjectID AND (@LastRunCreatedUtc IS NULL OR CreatedUtc >= DATEADD(minute, -30, @LastRunCreatedUtc)) ) SELECT @RunCount = COUNT(1), @CompletedRunCount = SUM(CASE WHEN Status IN (N'Completed', N'CompletedWithWarnings') THEN 1 ELSE 0 END), @FailedRunCount = SUM(CASE WHEN Status IN (N'Failed', N'Cancelled') THEN 1 ELSE 0 END), @ActiveRunCount = SUM(CASE WHEN Status IN (N'Pending', N'Running') THEN 1 ELSE 0 END), @CompletedScenes = SUM(ISNULL(CompletedScenes, 0)), @FailedScenes = SUM(ISNULL(FailedScenes, 0)) FROM ScopedRuns; SELECT @TotalExpectedScenes = COUNT(1) FROM dbo.Scenes scene INNER JOIN dbo.Chapters chapter ON chapter.ChapterID = scene.ChapterID AND chapter.BookID = @BookID AND chapter.IsArchived = 0 WHERE scene.IsArchived = 0; IF @RunCount > 0 AND @ActiveRunCount = 0 AND @FailedRunCount = 0 AND @TotalExpectedScenes > 0 AND @CompletedScenes + @FailedScenes >= @TotalExpectedScenes BEGIN UPDATE dbo.StoryIntelligenceBookPipelines SET CurrentStage = N'CharacterReview', LastCompletedStage = N'SceneImport', CurrentReviewStage = N'CharacterReview', Status = N'NeedsReview', CompletedUtc = NULL, LastRunID = COALESCE(@LastRunID, LastRunID), UpdatedUtc = @Now WHERE StoryIntelligenceBookPipelineID = @ImportSessionID AND Status = N'InProgress' AND CurrentStage = N'Chapters'; IF @@ROWCOUNT > 0 SET @CompletedNow = 1; END; COMMIT TRANSACTION; IF @CompletedNow = 1 BEGIN SELECT @ImportSessionID AS StoryIntelligenceBookPipelineID, @ProjectID AS ProjectID, @BookID AS BookID, @UserID AS UserID, @LastRunID AS LastRunID, N'NeedsReview' AS Status, N'CharacterReview' AS CurrentStage, N'SceneImport' AS LastCompletedStage, N'CharacterReview' AS CurrentReviewStage, @RunCount AS RunCount, @CompletedRunCount AS CompletedRunCount, @FailedRunCount AS FailedRunCount, @TotalExpectedScenes AS TotalExpectedScenes, @CompletedScenes AS CompletedScenes, @FailedScenes AS FailedScenes, @CompletedNow AS CompletedNow; END; END; GO CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceBookPipeline_TryCompleteNextReadySceneAnalysis AS BEGIN SET NOCOUNT ON; DECLARE @BookID int; DECLARE @UserID int; SELECT TOP (1) @BookID = pipeline.BookID, @UserID = latest.UserID FROM dbo.StoryIntelligenceBookPipelines pipeline CROSS APPLY ( SELECT TOP (1) run.UserID, run.CreatedUtc FROM dbo.StoryIntelligenceRuns run WHERE run.BookID = pipeline.BookID AND run.ProjectID = pipeline.ProjectID ORDER BY run.CreatedUtc DESC, run.StoryIntelligenceRunID DESC ) latest WHERE pipeline.Status = N'InProgress' AND pipeline.CurrentStage = N'Chapters' AND NOT EXISTS ( SELECT 1 FROM dbo.StoryIntelligenceRuns activeRun WHERE activeRun.BookID = pipeline.BookID AND activeRun.ProjectID = pipeline.ProjectID AND activeRun.UserID = latest.UserID AND activeRun.CreatedUtc >= DATEADD(minute, -30, latest.CreatedUtc) AND activeRun.Status IN (N'Pending', N'Running') ) AND NOT EXISTS ( SELECT 1 FROM dbo.StoryIntelligenceRuns failedRun WHERE failedRun.BookID = pipeline.BookID AND failedRun.ProjectID = pipeline.ProjectID AND failedRun.UserID = latest.UserID AND failedRun.CreatedUtc >= DATEADD(minute, -30, latest.CreatedUtc) AND failedRun.Status IN (N'Failed', N'Cancelled') ) AND ( SELECT COUNT(1) FROM dbo.Scenes scene INNER JOIN dbo.Chapters chapter ON chapter.ChapterID = scene.ChapterID AND chapter.BookID = pipeline.BookID AND chapter.IsArchived = 0 WHERE scene.IsArchived = 0 ) > 0 AND ( SELECT SUM(ISNULL(run.CompletedScenes, 0) + ISNULL(run.FailedScenes, 0)) FROM dbo.StoryIntelligenceRuns run WHERE run.BookID = pipeline.BookID AND run.ProjectID = pipeline.ProjectID AND run.UserID = latest.UserID AND run.CreatedUtc >= DATEADD(minute, -30, latest.CreatedUtc) ) >= ( SELECT COUNT(1) FROM dbo.Scenes scene INNER JOIN dbo.Chapters chapter ON chapter.ChapterID = scene.ChapterID AND chapter.BookID = pipeline.BookID AND chapter.IsArchived = 0 WHERE scene.IsArchived = 0 ) ORDER BY pipeline.UpdatedUtc, pipeline.StoryIntelligenceBookPipelineID; IF @BookID IS NULL OR @UserID IS NULL RETURN; EXEC dbo.StoryIntelligenceBookPipeline_TryCompleteSceneAnalysis @BookID = @BookID, @UserID = @UserID; END; GO