From 49e5f653ddf80ba424a3f2d40045c9b86261afd0 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Wed, 29 Apr 2026 23:18:08 +0200 Subject: [PATCH] Persist aligned packet structure memory upstream --- .../HyperTwistCoachDashboardWidget.cpp | 43 ++-- .../HyperTwistTrainingCoachLibrary.cpp | 75 ++++--- .../HyperTwistTrainingRepositoryLibrary.cpp | 193 ++++++++++++++++++ .../HyperTwistTrainingSubsystem.cpp | 53 ++++- .../HyperTwistTrainingTypes.h | 24 +++ 5 files changed, 346 insertions(+), 42 deletions(-) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 0c4988a..35144b8 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -323,6 +323,19 @@ namespace HyperTwistCoachDashboardWidgetInternal || SourceLabel.StartsWith(TEXT("coach-memory-method-drill-recovery-")); } + bool IsAlignedTightFollowUpGuidanceSourceLabel(const FString& SourceLabel) + { + return SourceLabel == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + || SourceLabel == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up"); + } + + bool IsAlignedBroadRecommendedGuidanceSourceLabel(const FString& SourceLabel) + { + return SourceLabel == TEXT("recommendation-history-aligned-broad-recommended-outcome") + || SourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended"); + } + FString DescribeCoachMemorySourceLabel(const FString& SourceLabel) { if (SourceLabel == TEXT("coach-memory-dashboard-deferred-overflow-follow-up")) @@ -361,13 +374,19 @@ namespace HyperTwistCoachDashboardWidgetInternal { return TEXT("accepted drill-driven recommended handoff history"); } - if (SourceLabel == TEXT("recommendation-history-aligned-tight-follow-up-outcome")) + if (IsAlignedTightFollowUpGuidanceSourceLabel(SourceLabel)) { - return TEXT("aligned tight launched-plan follow-up outcome history"); + return SourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up") + ? TEXT("aligned tight retained follow-up-packet structure history") + : TEXT("aligned tight launched-plan follow-up outcome history"); } - if (SourceLabel == TEXT("recommendation-history-aligned-broad-recommended-outcome")) + if (IsAlignedBroadRecommendedGuidanceSourceLabel(SourceLabel)) { - return TEXT("aligned broad launched-plan recommended outcome history"); + return SourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended") + ? TEXT("aligned broad retained recommended-packet structure history") + : TEXT("aligned broad launched-plan recommended outcome history"); } if (SourceLabel == TEXT("coach-memory-dashboard-method-drill-recovery-strong-queued")) { @@ -8105,11 +8124,11 @@ void UHyperTwistCoachDashboardWidget::RecordCoachHandoffHistorySnapshot( Entry.AcceptedRecommendedHandoffCount - PreviousAcceptedRecommendedHandoffCount ); const bool bAlignedTightFollowUpGuidanceOutcomeSource = - CachedCoachPanelState.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome"); + HyperTwistCoachDashboardWidgetInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + CachedCoachPanelState.PreferredGuidanceSourceLabel); const bool bAlignedBroadRecommendedGuidanceOutcomeSource = - CachedCoachPanelState.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome"); + HyperTwistCoachDashboardWidgetInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + CachedCoachPanelState.PreferredGuidanceSourceLabel); Entry.AcceptedAlignedTightFollowUpOutcomeHandoffCount = PreviousAcceptedAlignedTightFollowUpOutcomeHandoffCount + (bAlignedTightFollowUpGuidanceOutcomeSource ? AcceptedFollowUpHandoffDelta : 0); @@ -11090,11 +11109,11 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() CachedCoachPanelState.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeAverageScore, CachedCoachPanelState.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeHistoryCount, CachedCoachPanelState.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore, - CachedCoachPanelState.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + HyperTwistCoachDashboardWidgetInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + CachedCoachPanelState.PreferredGuidanceSourceLabel) ? TEXT(" | Follow-up is currently being reinforced by aligned tight launched-plan lane outcomes.") - : (CachedCoachPanelState.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome") + : (HyperTwistCoachDashboardWidgetInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + CachedCoachPanelState.PreferredGuidanceSourceLabel) ? TEXT(" | Recommended is currently being reinforced by aligned broad launched-plan lane outcomes.") : TEXT("")) ); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp index 1783deb..163f7d9 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp @@ -330,6 +330,19 @@ namespace HyperTwistTrainingCoachLibraryInternal || IsMethodDrillRecoveryMemorySource(SourceLabel); } + bool IsAlignedTightFollowUpGuidanceSourceLabel(const FString& SourceLabel) + { + return SourceLabel == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + || SourceLabel == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up"); + } + + bool IsAlignedBroadRecommendedGuidanceSourceLabel(const FString& SourceLabel) + { + return SourceLabel == TEXT("recommendation-history-aligned-broad-recommended-outcome") + || SourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended"); + } + FString DescribeCoachMemorySourceLabel(const FString& SourceLabel) { if (SourceLabel == TEXT("coach-memory-dashboard-deferred-first-follow-up")) @@ -380,13 +393,19 @@ namespace HyperTwistTrainingCoachLibraryInternal { return TEXT("accepted drill-driven recommended handoff history"); } - if (SourceLabel == TEXT("recommendation-history-aligned-tight-follow-up-outcome")) + if (IsAlignedTightFollowUpGuidanceSourceLabel(SourceLabel)) { - return TEXT("aligned tight launched-plan follow-up outcome history"); + return SourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up") + ? TEXT("aligned tight retained follow-up-packet structure history") + : TEXT("aligned tight launched-plan follow-up outcome history"); } - if (SourceLabel == TEXT("recommendation-history-aligned-broad-recommended-outcome")) + if (IsAlignedBroadRecommendedGuidanceSourceLabel(SourceLabel)) { - return TEXT("aligned broad launched-plan recommended outcome history"); + return SourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended") + ? TEXT("aligned broad retained recommended-packet structure history") + : TEXT("aligned broad launched-plan recommended outcome history"); } if (SourceLabel == TEXT("coach-memory-dashboard-method-drill-recovery-strong-queued")) { @@ -2494,23 +2513,23 @@ FHyperTwistCoachBrief UHyperTwistTrainingCoachLibrary::DeriveCoachFollowUpBrief( HyperTwistTrainingCoachLibraryInternal::DescribeMethodDrillFollowUpPacketLane( MethodDrillFollowUpPacketHandoffKind); const FString AlignedGuidanceOutcomeSourceLabel = - ActionPlan.PreferredCoachHandoffSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome") - || ActionPlan.PreferredCoachHandoffSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome") + HyperTwistTrainingCoachLibraryInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + ActionPlan.PreferredCoachHandoffSourceLabel) + || HyperTwistTrainingCoachLibraryInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + ActionPlan.PreferredCoachHandoffSourceLabel) ? ActionPlan.PreferredCoachHandoffSourceLabel - : ((ActionPlan.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome")) - || (ActionPlan.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome")) + : (HyperTwistTrainingCoachLibraryInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + ActionPlan.PreferredGuidanceSourceLabel) + || HyperTwistTrainingCoachLibraryInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + ActionPlan.PreferredGuidanceSourceLabel) ? ActionPlan.PreferredGuidanceSourceLabel : FString()); const bool bAlignedTightFollowUpOutcomeSource = - AlignedGuidanceOutcomeSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome"); + HyperTwistTrainingCoachLibraryInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + AlignedGuidanceOutcomeSourceLabel); const bool bAlignedBroadRecommendedOutcomeSource = - AlignedGuidanceOutcomeSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome"); + HyperTwistTrainingCoachLibraryInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + AlignedGuidanceOutcomeSourceLabel); const FString AlignedGuidanceOutcomeSourceDescription = AlignedGuidanceOutcomeSourceLabel.IsEmpty() ? TEXT("none") @@ -3133,24 +3152,24 @@ FHyperTwistCoachSessionQueueSummary UHyperTwistTrainingCoachLibrary::DeriveCoach CoachMemorySnapshot.PreferredCoachHandoffSourceLabel, CoachMemorySnapshot.PreferredCoachHandoffKind)); const FString AlignedGuidanceOutcomeSourceLabel = - CoachMemorySnapshot.PreferredCoachHandoffSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome") - || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome") + HyperTwistTrainingCoachLibraryInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + CoachMemorySnapshot.PreferredCoachHandoffSourceLabel) + || HyperTwistTrainingCoachLibraryInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + CoachMemorySnapshot.PreferredCoachHandoffSourceLabel) ? CoachMemorySnapshot.PreferredCoachHandoffSourceLabel - : ((CoachMemorySnapshot.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome")) - || (CoachMemorySnapshot.PreferredGuidanceSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome")) + : (HyperTwistTrainingCoachLibraryInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + CoachMemorySnapshot.PreferredGuidanceSourceLabel) + || HyperTwistTrainingCoachLibraryInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + CoachMemorySnapshot.PreferredGuidanceSourceLabel) ? CoachMemorySnapshot.PreferredGuidanceSourceLabel : FString()); const bool bAlignedTightFollowUpOutcomeContinuation = - AlignedGuidanceOutcomeSourceLabel - == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + HyperTwistTrainingCoachLibraryInternal::IsAlignedTightFollowUpGuidanceSourceLabel( + AlignedGuidanceOutcomeSourceLabel) && SourceLabel == TEXT("follow-up-brief"); const bool bAlignedBroadRecommendedOutcomeRedirect = - AlignedGuidanceOutcomeSourceLabel - == TEXT("recommendation-history-aligned-broad-recommended-outcome") + HyperTwistTrainingCoachLibraryInternal::IsAlignedBroadRecommendedGuidanceSourceLabel( + AlignedGuidanceOutcomeSourceLabel) && SourceLabel == TEXT("primary-brief"); if (bNarrowedQueueContinuation || bNarrowedFollowUpContinuation diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp index 6604676..10ca0b5 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp @@ -779,6 +779,13 @@ namespace HyperTwistTrainingRepositoryLibraryInternal && TrainingSessionId.Contains(TEXT("method_drill_follow_up"), ESearchCase::IgnoreCase); } + bool IsCoachFollowUpTrainingSessionId(const FString& TrainingSessionId) + { + return !TrainingSessionId.IsEmpty() + && TrainingSessionId.Contains(TEXT("follow_up"), ESearchCase::IgnoreCase) + && !TrainingSessionId.Contains(TEXT("method_drill_follow_up"), ESearchCase::IgnoreCase); + } + bool IsNarrowMethodDrillFollowUpPacketStructureSessionId(const FString& TrainingSessionId) { return !TrainingSessionId.IsEmpty() @@ -791,6 +798,24 @@ namespace HyperTwistTrainingRepositoryLibraryInternal && TrainingSessionId.Contains(TEXT("__packet_broad_"), ESearchCase::IgnoreCase); } + bool IsAlignedTightCoachFollowUpPacketStructureSessionId(const FString& TrainingSessionId) + { + return !TrainingSessionId.IsEmpty() + && TrainingSessionId.Contains( + TEXT("__aligned_packet_tight_follow_up"), + ESearchCase::IgnoreCase + ); + } + + bool IsAlignedBroadCoachFollowUpPacketStructureSessionId(const FString& TrainingSessionId) + { + return !TrainingSessionId.IsEmpty() + && TrainingSessionId.Contains( + TEXT("__aligned_packet_broad_recommended"), + ESearchCase::IgnoreCase + ); + } + float ResolveMethodDrillFollowUpOutcomeScore(const FHyperTwistTrainingRunRecord& RunRecord) { if (!RunRecord.IsStructurallyValid()) @@ -824,6 +849,11 @@ namespace HyperTwistTrainingRepositoryLibraryInternal ); } + float ResolveCoachFollowUpOutcomeScore(const FHyperTwistTrainingRunRecord& RunRecord) + { + return ResolveMethodDrillFollowUpOutcomeScore(RunRecord); + } + TArray DeduplicateTemplateCaseIds(const TArray& FocusCaseIds) { TArray UniqueCaseIds; @@ -2231,8 +2261,12 @@ namespace HyperTwistTrainingRepositoryLibraryInternal const bool bAlignedTightFollowUpGuidanceOutcomeSource = CoachMemorySnapshot.PreferredGuidanceSourceLabel == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + || CoachMemorySnapshot.PreferredGuidanceSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up") || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up") || (CoachMemorySnapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp && CoachMemorySnapshot.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeHistoryCount >= 2 @@ -2245,8 +2279,12 @@ namespace HyperTwistTrainingRepositoryLibraryInternal const bool bAlignedBroadRecommendedGuidanceOutcomeSource = CoachMemorySnapshot.PreferredGuidanceSourceLabel == TEXT("recommendation-history-aligned-broad-recommended-outcome") + || CoachMemorySnapshot.PreferredGuidanceSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended") || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel == TEXT("recommendation-history-aligned-broad-recommended-outcome") + || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended") || (CoachMemorySnapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::Recommended && CoachMemorySnapshot.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeHistoryCount >= 2 @@ -8324,6 +8362,161 @@ FHyperTwistTrainingCoachMemorySnapshot UHyperTwistTrainingRepositoryLibrary::Der || ArchivePolicy.bNeedsArchiveRetentionTuning; } + TArray AlignedCoachFollowUpRunRecords; + AlignedCoachFollowUpRunRecords.Reserve(RepositoryState.RunRecords.Num()); + for (const FHyperTwistTrainingRunRecord& RunRecord : RepositoryState.RunRecords) + { + if (!RunRecord.IsStructurallyValid() + || RunRecord.Session.UserId != UserId + || !HyperTwistTrainingRepositoryLibraryInternal::IsCoachFollowUpTrainingSessionId( + RunRecord.Session.TrainingSessionId)) + { + continue; + } + + if (!HyperTwistTrainingRepositoryLibraryInternal::IsAlignedTightCoachFollowUpPacketStructureSessionId( + RunRecord.Session.TrainingSessionId) + && !HyperTwistTrainingRepositoryLibraryInternal::IsAlignedBroadCoachFollowUpPacketStructureSessionId( + RunRecord.Session.TrainingSessionId)) + { + continue; + } + + AlignedCoachFollowUpRunRecords.Add(RunRecord); + } + + if (AlignedCoachFollowUpRunRecords.Num() > 0) + { + AlignedCoachFollowUpRunRecords = + HyperTwistTrainingRepositoryLibraryInternal::SortRunRecordsByUpdateUtc( + AlignedCoachFollowUpRunRecords); + const int32 FirstRelevantIndex = FMath::Max(0, AlignedCoachFollowUpRunRecords.Num() - 8); + float AlignedTightOutcomeAccumulator = 0.0f; + float AlignedBroadOutcomeAccumulator = 0.0f; + for (int32 Index = FirstRelevantIndex; Index < AlignedCoachFollowUpRunRecords.Num(); ++Index) + { + const FHyperTwistTrainingRunRecord& RunRecord = AlignedCoachFollowUpRunRecords[Index]; + const float OutcomeScore = + HyperTwistTrainingRepositoryLibraryInternal::ResolveCoachFollowUpOutcomeScore( + RunRecord); + if (HyperTwistTrainingRepositoryLibraryInternal::IsAlignedTightCoachFollowUpPacketStructureSessionId( + RunRecord.Session.TrainingSessionId)) + { + Snapshot.AlignedTightFollowUpPacketStructureHistoryCount += 1; + AlignedTightOutcomeAccumulator += OutcomeScore; + } + else if (HyperTwistTrainingRepositoryLibraryInternal::IsAlignedBroadCoachFollowUpPacketStructureSessionId( + RunRecord.Session.TrainingSessionId)) + { + Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount += 1; + AlignedBroadOutcomeAccumulator += OutcomeScore; + } + } + + if (Snapshot.AlignedTightFollowUpPacketStructureHistoryCount > 0) + { + Snapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore = + AlignedTightOutcomeAccumulator + / static_cast(Snapshot.AlignedTightFollowUpPacketStructureHistoryCount); + } + if (Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount > 0) + { + Snapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore = + AlignedBroadOutcomeAccumulator + / static_cast(Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount); + } + + const bool bAlignedTightPacketStructureHistory = + Snapshot.AlignedTightFollowUpPacketStructureHistoryCount >= 2 + && Snapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore >= 60.0f + && (Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount <= 0 + || Snapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore + >= Snapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore - 2.0f); + const bool bAlignedBroadPacketStructureHistory = + Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount >= 2 + && Snapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore >= 58.0f + && (Snapshot.AlignedTightFollowUpPacketStructureHistoryCount <= 0 + || Snapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore + >= Snapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore - 2.0f); + if (bAlignedTightPacketStructureHistory + && (!bAlignedBroadPacketStructureHistory + || Snapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore + >= Snapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore)) + { + const int32 AlignedTightPacketStructureBias = FMath::Clamp( + Snapshot.AlignedTightFollowUpPacketStructureHistoryCount + - Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount + + (Snapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore >= 78.0f + ? 1 + : 0), + 1, + 4 + ); + Snapshot.FollowUpGuidanceContinueBias += AlignedTightPacketStructureBias; + Snapshot.SuppressedPrimaryQueuePressureCount += FMath::Max( + 1, + AlignedTightPacketStructureBias - 1 + ); + if (Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::None + || Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::Recommended + || Snapshot.PreferredGuidanceSourceLabel.StartsWith(TEXT("recommendation-history")) + || Snapshot.PreferredGuidanceSourceLabel.StartsWith( + TEXT("coach-memory-aligned-follow-up-packet-structure"))) + { + Snapshot.PreferredGuidanceLane = EHyperTwistTrainingCoachGuidanceLane::FollowUp; + Snapshot.PreferredGuidanceSourceLabel = + TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up"); + } + if (Snapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::None + || Snapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::Recommended + || Snapshot.PreferredCoachHandoffSourceLabel.IsEmpty() + || Snapshot.PreferredCoachHandoffSourceLabel.StartsWith(TEXT("recommendation-history")) + || Snapshot.PreferredCoachHandoffSourceLabel.StartsWith( + TEXT("coach-memory-aligned-follow-up-packet-structure"))) + { + Snapshot.PreferredCoachHandoffKind = EHyperTwistTrainingCoachHandoffKind::FollowUp; + Snapshot.PreferredCoachHandoffSourceLabel = + TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up"); + } + } + else if (bAlignedBroadPacketStructureHistory) + { + const int32 AlignedBroadPacketStructureBias = FMath::Clamp( + Snapshot.AlignedBroadRecommendedPacketStructureHistoryCount + - Snapshot.AlignedTightFollowUpPacketStructureHistoryCount + + (Snapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore >= 76.0f + ? 1 + : 0), + 1, + 4 + ); + Snapshot.RecommendedGuidanceContinueBias += AlignedBroadPacketStructureBias; + Snapshot.SuppressedFollowUpQueuePressureCount += AlignedBroadPacketStructureBias; + if (Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::None + || Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp + || Snapshot.PreferredGuidanceSourceLabel.StartsWith(TEXT("recommendation-history")) + || Snapshot.PreferredGuidanceSourceLabel.StartsWith( + TEXT("coach-memory-aligned-follow-up-packet-structure"))) + { + Snapshot.PreferredGuidanceLane = EHyperTwistTrainingCoachGuidanceLane::Recommended; + Snapshot.PreferredGuidanceSourceLabel = + TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended"); + } + if (Snapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::None + || Snapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::FollowUp + || Snapshot.PreferredCoachHandoffSourceLabel.IsEmpty() + || Snapshot.PreferredCoachHandoffSourceLabel.StartsWith(TEXT("recommendation-history")) + || Snapshot.PreferredCoachHandoffSourceLabel.StartsWith( + TEXT("coach-memory-aligned-follow-up-packet-structure"))) + { + Snapshot.PreferredCoachHandoffKind = + EHyperTwistTrainingCoachHandoffKind::Recommended; + Snapshot.PreferredCoachHandoffSourceLabel = + TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended"); + } + } + } + const TArray QueueStates = ListCoachSessionQueueStatesForUser(RepositoryState, UserId); if (QueueStates.Num() > 0) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp index 2de67f1..6253df8 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp @@ -358,6 +358,39 @@ namespace HyperTwistTrainingSubsystemInternal return FString(); } + FString ResolveAlignedCoachFollowUpPacketStructureToken( + const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot) + { + const bool bAlignedTightFollowUpPacketSource = + CoachMemorySnapshot.PreferredGuidanceSourceLabel + == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel + == TEXT("recommendation-history-aligned-tight-follow-up-outcome") + || CoachMemorySnapshot.PreferredGuidanceSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up") + || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up"); + const bool bAlignedBroadRecommendedPacketSource = + CoachMemorySnapshot.PreferredGuidanceSourceLabel + == TEXT("recommendation-history-aligned-broad-recommended-outcome") + || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel + == TEXT("recommendation-history-aligned-broad-recommended-outcome") + || CoachMemorySnapshot.PreferredGuidanceSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended") + || CoachMemorySnapshot.PreferredCoachHandoffSourceLabel + == TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended"); + if (bAlignedTightFollowUpPacketSource && !bAlignedBroadRecommendedPacketSource) + { + return TEXT("aligned_packet_tight_follow_up_first"); + } + if (bAlignedBroadRecommendedPacketSource && !bAlignedTightFollowUpPacketSource) + { + return TEXT("aligned_packet_broad_recommended_first"); + } + + return FString(); + } + FHyperTwistTrainingSessionTemplate ApplyMethodDrillFollowUpMemoryBias( const FHyperTwistTrainingSessionTemplate& SessionTemplate, const FHyperTwistTrainingMethodDrillDiagnosticPacket& DiagnosticPacket, @@ -823,6 +856,14 @@ FHyperTwistTrainingCoachPanelState UHyperTwistTrainingSubsystem::GetActiveCoachP ActiveCoachMemorySnapshot.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeAverageScore; PanelState.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore = ActiveCoachMemorySnapshot.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore; + PanelState.AlignedTightFollowUpPacketStructureHistoryCount = + ActiveCoachMemorySnapshot.AlignedTightFollowUpPacketStructureHistoryCount; + PanelState.AlignedBroadRecommendedPacketStructureHistoryCount = + ActiveCoachMemorySnapshot.AlignedBroadRecommendedPacketStructureHistoryCount; + PanelState.AlignedTightFollowUpPacketStructureAverageOutcomeScore = + ActiveCoachMemorySnapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore; + PanelState.AlignedBroadRecommendedPacketStructureAverageOutcomeScore = + ActiveCoachMemorySnapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore; PanelState.bRepositoryVerificationPassed = ActiveRepositoryRoundTripVerification.bDidRoundTripPass; PanelState.bRepositoryVerificationNeedsAttention = ActiveRepositoryRoundTripVerification.ResolvedPath.IsEmpty() || !ActiveRepositoryRoundTripVerification.bDidRoundTripPass; @@ -2148,11 +2189,19 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachFollowUpRun( ); const TArray LaunchedCaseIds = HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(FollowUpDeck); + const FString AlignedPacketStructureToken = + HyperTwistTrainingSubsystemInternal::ResolveAlignedCoachFollowUpPacketStructureToken( + ActiveCoachMemorySnapshot); + const FString StructuredSessionId = !AlignedPacketStructureToken.IsEmpty() + ? (!SessionId.IsEmpty() + ? FString::Printf(TEXT("%s__%s"), *SessionId, *AlignedPacketStructureToken) + : FString::Printf(TEXT("coach_follow_up__%s"), *AlignedPacketStructureToken)) + : SessionId; const FHyperTwistTrainingCoachActionPlan DraftActionPlan = UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan( FollowUpBrief, ActiveCoachMemorySnapshot, - FString::Printf(TEXT("coach_follow_up_%s"), *SessionId), + FString::Printf(TEXT("coach_follow_up_%s"), *StructuredSessionId), FString(), LaunchBudget.RequestedCaseCount, FollowUpDeck.Cases.Num(), @@ -2162,7 +2211,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachFollowUpRun( FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck( FollowUpDeck, FollowUpBrief.UserId, - SessionId, + StructuredSessionId, FollowUpBrief.SuggestedMode ); if (!RunState.IsStructurallyValid() || !DraftActionPlan.IsStructurallyValid()) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index 20acd01..364cf27 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -2019,6 +2019,18 @@ struct FHyperTwistTrainingCoachMemorySnapshot UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") float ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore = 0.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 AlignedTightFollowUpPacketStructureHistoryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 AlignedBroadRecommendedPacketStructureHistoryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + float AlignedTightFollowUpPacketStructureAverageOutcomeScore = 0.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + float AlignedBroadRecommendedPacketStructureAverageOutcomeScore = 0.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") bool bNeedsCoachIntervention = false; @@ -5182,6 +5194,18 @@ struct FHyperTwistTrainingCoachPanelState UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") float ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore = 0.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 AlignedTightFollowUpPacketStructureHistoryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 AlignedBroadRecommendedPacketStructureHistoryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + float AlignedTightFollowUpPacketStructureAverageOutcomeScore = 0.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + float AlignedBroadRecommendedPacketStructureAverageOutcomeScore = 0.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") int32 SignalCount = 0;