Order relationship review by first appearance

This commit is contained in:
Nick Beckley 2026-08-29 13:23:52 +00:00
parent ae0552af90
commit feed4549bf
2 changed files with 19 additions and 1 deletions

View File

@ -54,6 +54,7 @@ var tests = new (string Name, Action Test)[]
("Relationship events preserve chronological story order", RelationshipEventsPreserveChronologicalStoryOrder),
("Relationship progression keeps chronological state", RelationshipProgressionKeepsChronologicalState),
("Relationship observations do not create event spam", RelationshipObservationsDoNotCreateEventSpam),
("Relationship review orders by first story appearance", RelationshipReviewOrdersByFirstStoryAppearance),
("Knowledge signals map to existing knowledge states", KnowledgeSignalsMapToExistingStates),
("Knowledge recipient resolves narrator through POV", KnowledgeRecipientResolvesNarratorThroughPov),
("Knowledge identity reveal preserves subjective timing", KnowledgeIdentityRevealPreservesSubjectiveTiming),
@ -2200,6 +2201,14 @@ static void RelationshipObservationsDoNotCreateEventSpam()
Assert(!IsMeaningfulRelationshipEvent("trust", "Nora and Imani exchange gifts after years of friendship."), "The non-event rule should hold for unrelated fixture names too.");
}
static void RelationshipReviewOrdersByFirstStoryAppearance()
{
var service = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine/Services/StoryIntelligenceRelationshipImportService.cs"));
Assert(service.Contains(".OrderBy(CandidateFirstStoryOrder)", StringComparison.Ordinal), "Relationship review candidates should be ordered by first story appearance.");
Assert(service.Contains("private static (decimal ChapterNumber, decimal SceneNumber, int SortOrder, int SceneID) CandidateFirstStoryOrder", StringComparison.Ordinal), "Relationship review should calculate first appearance from chapter/scene order.");
Assert(!service.Contains(".OrderByDescending(candidate => candidate.Appearances.Select(appearance => appearance.SceneID).Distinct().Count())", StringComparison.Ordinal), "Relationship review should not prioritise frequent relationships ahead of earlier first appearances.");
}
static void KnowledgeSignalsMapToExistingStates()
{
var states = new List<KnowledgeState>

View File

@ -306,7 +306,7 @@ public sealed class StoryIntelligenceRelationshipImportService(
var candidates = groups.Values
.Where(candidate => candidate.Appearances.Any(appearance => !appearance.AlreadyLinked))
.OrderByDescending(candidate => candidate.Appearances.Select(appearance => appearance.SceneID).Distinct().Count())
.OrderBy(CandidateFirstStoryOrder)
.ThenBy(candidate => candidate.CharacterAName)
.ThenBy(candidate => candidate.CharacterBName)
.ToList();
@ -588,6 +588,15 @@ public sealed class StoryIntelligenceRelationshipImportService(
private static (decimal ChapterNumber, decimal SceneNumber, int SortOrder, int SceneID) StoryOrder(RelationshipAppearanceImport appearance)
=> (appearance.ChapterNumber, appearance.SceneNumber, appearance.SortOrder, appearance.SceneID);
private static (decimal ChapterNumber, decimal SceneNumber, int SortOrder, int SceneID) CandidateFirstStoryOrder(RelationshipCandidate candidate)
=> candidate.Appearances
.Select(StoryOrder)
.OrderBy(order => order.ChapterNumber)
.ThenBy(order => order.SceneNumber)
.ThenBy(order => order.SortOrder)
.ThenBy(order => order.SceneID)
.FirstOrDefault((decimal.MaxValue, decimal.MaxValue, int.MaxValue, int.MaxValue));
private static string RelationshipStateAtScene(
string initialState,
IEnumerable<(int SceneID, decimal ChapterNumber, decimal SceneNumber, int SortOrder, string StateName)> events,