Allow completed character review inspection
This commit is contained in:
parent
9c1f9c9182
commit
07113f9b36
@ -281,6 +281,7 @@ var tests = new (string Name, Action Test)[]
|
||||
("Story Intelligence Review Centre adds no AI calls", StoryIntelligenceReviewCentreAddsNoAiCalls),
|
||||
("Story Intelligence Review Centre uses bounded summary query", StoryIntelligenceReviewCentreUsesBoundedSummaryQuery),
|
||||
("Story Intelligence detailed review GETs use selected module paths", StoryIntelligenceDetailedReviewGetsUseSelectedModulePaths),
|
||||
("Story Intelligence completed Character review remains inspectable", StoryIntelligenceCompletedCharacterReviewRemainsInspectable),
|
||||
("Story Intelligence detailed reviews read persisted candidate pages", StoryIntelligenceDetailedReviewsReadPersistedCandidatePages),
|
||||
("Story Intelligence Job 6 uses bounded concurrent chapter execution", StoryIntelligenceJob6UsesBoundedConcurrentChapterExecution),
|
||||
("Story Intelligence global progress uses whole run scene totals", StoryIntelligenceGlobalProgressUsesWholeRunSceneTotals),
|
||||
@ -1138,6 +1139,41 @@ static void StoryIntelligenceDetailedReviewGetsUseSelectedModulePaths()
|
||||
Assert(!persistedReviewService.Contains("GetRunAsync", StringComparison.Ordinal), "Persisted review GET service must not traverse old run batches.");
|
||||
}
|
||||
|
||||
static void StoryIntelligenceCompletedCharacterReviewRemainsInspectable()
|
||||
{
|
||||
var root = PlotLineRoot();
|
||||
var controller = File.ReadAllText(Path.Combine(root, "Controllers/OnboardingController.cs"));
|
||||
var onboarding = File.ReadAllText(Path.Combine(root, "Services/OnboardingStoryIntelligenceService.cs"));
|
||||
var candidateService = File.ReadAllText(Path.Combine(root, "Services/StoryIntelligenceReviewCandidateService.cs"));
|
||||
var view = File.ReadAllText(Path.Combine(root, "Views/Onboarding/StoryIntelligenceCharacters.cshtml"));
|
||||
|
||||
var action = ExtractAction(controller, "public async Task<IActionResult> StoryIntelligenceCharacters");
|
||||
Assert(action.Contains("GetCharacterReviewAsync(batchId, page)", StringComparison.Ordinal), "Character GET should use the selected persisted Character review path.");
|
||||
Assert(!action.Contains("CharacterReview.Candidates.Count == 0", StringComparison.Ordinal), "Completed empty Character review must not redirect to Review Centre.");
|
||||
Assert(!action.Contains("CharacterGateSatisfied &&", StringComparison.Ordinal), "Character completion must not be treated as an access blocker.");
|
||||
Assert(action.TrimEnd().EndsWith("return View(model);\n }", StringComparison.Ordinal), "Character GET should render the Character page when scene analysis is complete.");
|
||||
Assert(!action.Contains("PrepareCharacterCandidatesAsync", StringComparison.Ordinal), "Character GET must not regenerate candidates.");
|
||||
Assert(!action.Contains("RecordCharacterImportAsync", StringComparison.Ordinal), "Character GET must not alter CharacterReviewCompletedUtc.");
|
||||
Assert(!action.Contains("RecordLocationImportAsync", StringComparison.Ordinal), "Character GET must not alter Location completion.");
|
||||
Assert(!action.Contains("RecordAssetImportAsync", StringComparison.Ordinal), "Character GET must not alter Asset completion.");
|
||||
Assert(!action.Contains("RecordRelationshipImportAsync", StringComparison.Ordinal), "Character GET must not alter Relationship completion.");
|
||||
Assert(!action.Contains("RecordKnowledgeImportAsync", StringComparison.Ordinal), "Character GET must not alter Knowledge completion.");
|
||||
|
||||
var selectedReview = ExtractBetween(onboarding, "public Task<StoryIntelligenceProgressViewModel?> GetCharacterReviewAsync", "public Task<StoryIntelligenceProgressViewModel?> GetLocationReviewAsync");
|
||||
Assert(selectedReview.Contains("reviewCandidates.GetCharacterReviewAsync(frame.Batch, pageNumber, pageSize)", StringComparison.Ordinal), "Completed Character page should hydrate from persisted review/canonical data.");
|
||||
Assert(!selectedReview.Contains("PrepareCharacterCandidatesAsync", StringComparison.Ordinal), "Selected Character GET must not prepare candidates.");
|
||||
Assert(!selectedReview.Contains("RecordCharacterImportAsync", StringComparison.Ordinal), "Selected Character GET must not mark completion.");
|
||||
|
||||
var getReview = ExtractBetween(candidateService, "public async Task<StoryIntelligenceCharacterReviewViewModel> GetCharacterReviewAsync", "public async Task<StoryIntelligenceLocationReviewViewModel> GetLocationReviewAsync");
|
||||
Assert(getReview.Contains("AliasTargetOptions = existingOptions", StringComparison.Ordinal), "Completed Character page should expose canonical resolved characters for inspection.");
|
||||
Assert(!getReview.Contains("BuildReviewAsync", StringComparison.Ordinal), "Persisted Character GET must not rebuild candidates.");
|
||||
Assert(!getReview.Contains("MarkReviewedAsync", StringComparison.Ordinal), "Persisted Character GET must not change decisions.");
|
||||
|
||||
Assert(view.Contains("Character Review is complete.", StringComparison.Ordinal), "Completed Character page should state that the review is complete.");
|
||||
Assert(view.Contains("Resolved character", StringComparison.Ordinal), "Completed Character page should list resolved canonical characters.");
|
||||
Assert(view.Contains("AliasTargetOptions", StringComparison.Ordinal), "Completed Character page should use canonical Character data when no pending candidates exist.");
|
||||
}
|
||||
|
||||
static void StoryIntelligenceDetailedReviewsReadPersistedCandidatePages()
|
||||
{
|
||||
var root = PlotLineRoot();
|
||||
|
||||
@ -339,9 +339,7 @@ public sealed class OnboardingController(
|
||||
return RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId });
|
||||
}
|
||||
|
||||
return model.CharacterGateSatisfied && model.CharacterReview.Candidates.Count == 0
|
||||
? RedirectToAction(nameof(StoryIntelligenceReviewCentre), new { batchId })
|
||||
: View(model);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet("story-intelligence/locations")]
|
||||
|
||||
@ -35,9 +35,23 @@
|
||||
@if (Model.CharacterReview.Candidates.Count == 0)
|
||||
{
|
||||
<div class="story-review-note">
|
||||
<strong>No character decisions are waiting.</strong>
|
||||
<p class="mb-0">Characters are already up to date, or there were no character suggestions ready to import.</p>
|
||||
<strong>Character Review is complete.</strong>
|
||||
<p class="mb-0">@Model.CharacterReview.AliasTargetOptions.Count.ToString("N0") resolved character@(Model.CharacterReview.AliasTargetOptions.Count == 1 ? string.Empty : "s") are available for this book.</p>
|
||||
</div>
|
||||
@if (Model.CharacterReview.AliasTargetOptions.Count > 0)
|
||||
{
|
||||
<div class="story-character-card-grid">
|
||||
@foreach (var character in Model.CharacterReview.AliasTargetOptions)
|
||||
{
|
||||
<article class="story-character-card">
|
||||
<div class="story-character-card__body">
|
||||
<strong>@character.CharacterName</strong>
|
||||
<p class="mb-0 text-muted">Resolved character</p>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="onboarding-actions">
|
||||
<a class="btn btn-outline-secondary" asp-action="StoryIntelligenceReviewCentre" asp-route-batchId="@Model.BatchID">Back to Review Centre</a>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user