@model StoryIntelligenceProgressViewModel @using System.Security.Claims @inject IConfiguration Configuration @{ ViewData["Title"] = "Review analysis"; var adminEmails = Configuration.GetSection("Admin:AllowedEmails").Get() ?? []; var userEmail = User.FindFirstValue(ClaimTypes.Email); var isAdmin = !string.IsNullOrWhiteSpace(userEmail) && adminEmails.Any(email => string.Equals(email, userEmail, StringComparison.OrdinalIgnoreCase)); var chaptersNeedingReview = Model.Chapters.Count(NeedsReview); var warningsCount = Model.Chapters.Sum(chapter => chapter.Warnings.Count + chapter.Blockers.Count + (chapter.FailedScenes ?? 0)); }

Step 9 of 9

Review Story Intelligence Results

PlotDirector has finished reading your manuscript. Nothing has been added to your project yet. Please review the detected scenes before creating them.

@if (TempData["OnboardingStoryIntelligenceError"] is string error) {
@error
} @if (TempData["OnboardingStoryIntelligenceMessage"] is string message) {
@message
}
Only scenes will be created. Characters, locations, assets, relationships and knowledge will be imported during later Story Intelligence phases.
Story Intelligence complete @Model.CompletedChapterCount.ToString("N0") chapter@(Model.CompletedChapterCount == 1 ? string.Empty : "s")
Scenes detected @Model.TotalDetectedScenes.ToString("N0")
Words analysed @Model.TotalAnalysedWords.ToString("N0")
Elapsed time @FormatDuration(Model.TotalDurationMs)
Estimated AI cost @FormatCost(Model.TotalEstimatedCostUSD)
Warnings requiring review @warningsCount.ToString("N0")
@foreach (var chapter in Model.Chapters.OrderBy(chapter => chapter.ChapterNumber)) {

Chapter @chapter.ChapterNumber

@chapter.ChapterTitle

@((chapter.TotalDetectedScenes ?? 0).ToString("N0")) scene@(chapter.TotalDetectedScenes == 1 ? string.Empty : "s") detected / confidence @FormatConfidence(chapter.AverageConfidence)

@FriendlyStatus(chapter)
Scenes found @((chapter.TotalDetectedScenes ?? 0).ToString("N0"))
Scenes ready @((chapter.CompletedScenes ?? 0).ToString("N0"))
Needs review @(((chapter.FailedScenes ?? 0) + chapter.Blockers.Count).ToString("N0"))
Confidence @FormatConfidence(chapter.AverageConfidence)
@if (!string.IsNullOrWhiteSpace(chapter.CommitMessage)) {

@chapter.CommitMessage

} @if (chapter.Warnings.Count > 0) {
Notes
    @foreach (var warning in chapter.Warnings) {
  • @warning
  • }
} @if (chapter.Blockers.Count > 0) {
Before scenes can be created
    @foreach (var blocker in chapter.Blockers) {
  • @blocker
  • }
} @if (!string.IsNullOrWhiteSpace(chapter.ErrorMessage)) {

@chapter.ErrorMessage

}
@if (chapter.Scenes.Count == 0) {

No readable scene previews are available for this chapter.

} else { @foreach (var scene in chapter.Scenes) {
Scene @scene.SceneNumber.ToString("N0") @if (scene.HasWarnings) { Review recommended }

@scene.Summary

POV
@Display(scene.Pov)
Setting
@Display(scene.Setting)
Confidence
@FormatConfidence(scene.Confidence)
} }
@if (isAdmin) {
Admin diagnostics
Run ID
@chapter.RunID
Status
@chapter.Status
Stage
@(chapter.CurrentStage ?? "-")
Failure stage
@(chapter.FailureStage ?? "-")
Tokens
@(chapter.TotalTokens?.ToString("N0") ?? "-")
}
}
Scene creation uses the existing PlotDirector import safeguards. Default empty Scene 1 placeholders can be replaced, duplicate imports are blocked, and failures roll back safely.
@if (Model.BatchID.HasValue) { Back @if (Model.HasReadyScenesToCreate) {
} else if (Model.AllCommitted) { Continue } }
@functions { private static bool NeedsReview(StoryIntelligenceOnboardingChapterViewModel chapter) => chapter.IsFailed || (chapter.FailedScenes ?? 0) > 0 || chapter.Blockers.Count > 0 || (!chapter.CanCommit && !chapter.HasCompletedCommit && chapter.IsRunComplete); private static string FriendlyStatus(StoryIntelligenceOnboardingChapterViewModel chapter) { if (chapter.HasCompletedCommit) { return "Scenes created"; } if (chapter.CanCommit) { return chapter.Warnings.Count > 0 ? "Ready with notes" : "Ready to create"; } return chapter.Status switch { StoryIntelligenceRunStatuses.Pending => "Waiting", StoryIntelligenceRunStatuses.Running => "Reading", StoryIntelligenceRunStatuses.Completed => "Needs attention", StoryIntelligenceRunStatuses.CompletedWithWarnings => "Needs attention", StoryIntelligenceRunStatuses.Failed => "Needs review", StoryIntelligenceRunStatuses.Cancelled => "Cancelled", _ => "Needs attention" }; } private static string StatusClass(StoryIntelligenceOnboardingChapterViewModel chapter) { if (chapter.HasCompletedCommit) { return "story-review-status story-review-status--created"; } if (chapter.CanCommit) { return "story-review-status story-review-status--ready"; } return chapter.IsActive ? "story-review-status story-review-status--active" : "story-review-status story-review-status--warning"; } private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value; private static string FormatConfidence(decimal? confidence) => confidence.HasValue ? $"{Math.Clamp(confidence.Value, 0m, 1m):P0}" : "Not available"; private static string FormatCost(decimal? cost) => cost.HasValue ? $"About ${cost.Value:0.00}" : "Not available"; private static string FormatDuration(long milliseconds) { var elapsed = TimeSpan.FromMilliseconds(Math.Max(0, milliseconds)); if (elapsed.TotalHours >= 1) { return $"{Math.Ceiling(elapsed.TotalHours):N0} hr"; } return elapsed.TotalMinutes >= 1 ? $"{Math.Max(1, (int)Math.Round(elapsed.TotalMinutes)):N0} min" : $"{Math.Max(0, (int)Math.Round(elapsed.TotalSeconds)):N0} sec"; } }