From 09f003b0cdedfa8217fa278f5444c70306c7612e Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Mon, 17 Aug 2026 19:33:38 +0000 Subject: [PATCH] Tighten single-word character candidate filtering --- PlotLine.Tests/Program.cs | 11 +++++++++++ PlotLine/Services/WordCompanionService.cs | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/PlotLine.Tests/Program.cs b/PlotLine.Tests/Program.cs index 2d1714c..ea5faf0 100644 --- a/PlotLine.Tests/Program.cs +++ b/PlotLine.Tests/Program.cs @@ -1302,6 +1302,17 @@ static void CharacterDiscoveryRejectsSentenceStartWords() Assert(candidates.Any(candidate => candidate.Text == "Debbie"), "Real common character names should still be detected."); Assert(candidates.Any(candidate => candidate.Text == "Mr Wilkinson"), "Titled character names should still be detected."); Assert(!candidates.Any(candidate => candidate.Text is "Silence" or "Morning" or "Eyes"), "Repeated sentence-start words must not become character candidates."); + + var actionText = """ + Door opened before anyone moved. Door closed behind them. + Glass shattered across the floor. Glass glittered under the counter. + Window rattled in the frame. Window shook again. + Colin opened the file. Debbie watched Colin. + """; + var actionCandidates = (IReadOnlyList)method!.Invoke(null, [actionText, false])!; + Assert(actionCandidates.Any(candidate => candidate.Text == "Colin"), "Known character names should still survive action evidence."); + Assert(actionCandidates.Any(candidate => candidate.Text == "Debbie"), "Known character names should still survive action evidence."); + Assert(!actionCandidates.Any(candidate => candidate.Text is "Door" or "Glass" or "Window"), "Repeated sentence-start action nouns must not become character candidates."); } static void StoryIntelligenceExperienceBootDoesNotSerialiseLiveModel() diff --git a/PlotLine/Services/WordCompanionService.cs b/PlotLine/Services/WordCompanionService.cs index d9ab1d4..f507b5f 100644 --- a/PlotLine/Services/WordCompanionService.cs +++ b/PlotLine/Services/WordCompanionService.cs @@ -744,7 +744,8 @@ public sealed class WordCompanionService( && !hasKnownGivenName && !hasNameLikeWord && evidence.PossessiveEvidenceCount == 0 - && nonSentenceStartMentions == 0) + && evidence.DialogueEvidenceCount == 0 + && nonSentenceStartMentions < 2) { score -= 5; } @@ -819,7 +820,16 @@ public sealed class WordCompanionService( && mostlySentenceStart && !hasNameEvidence && evidence.PossessiveEvidenceCount == 0 - && evidence.MentionCount - evidence.SentenceStartMentions == 0) + && evidence.DialogueEvidenceCount == 0 + && evidence.MentionCount - evidence.SentenceStartMentions < 2) + { + return "Excluded"; + } + if (isSingleWord + && !hasNameEvidence + && evidence.DialogueEvidenceCount == 0 + && evidence.PossessiveEvidenceCount == 0 + && evidence.MentionCount - evidence.SentenceStartMentions < 2) { return "Excluded"; }