diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index a68c381..8c36f19 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -1743,6 +1743,38 @@ namespace HyperTwistCoachDashboardWidgetInternal return TEXT("none"); } + int32 DeriveMethodDrillRecoveryPlanTightTrust( + const FMethodDrillRecoveryPlanComparisonSummary& Summary) + { + return Summary.TightPlanAlignedCount - Summary.TightPlanDivergedCount; + } + + int32 DeriveMethodDrillRecoveryPlanBroadTrust( + const FMethodDrillRecoveryPlanComparisonSummary& Summary) + { + return Summary.BroadPlanAlignedCount - Summary.BroadPlanDivergedCount; + } + + bool PrefersMethodDrillRecoveryPlanTightContinuation( + const FMethodDrillRecoveryPlanComparisonSummary& Summary) + { + const int32 TightTrust = DeriveMethodDrillRecoveryPlanTightTrust(Summary); + const int32 BroadTrust = DeriveMethodDrillRecoveryPlanBroadTrust(Summary); + return Summary.TightPlanSourceCount > 0 + && TightTrust > 0 + && TightTrust > BroadTrust; + } + + bool PrefersMethodDrillRecoveryPlanBroadRedirect( + const FMethodDrillRecoveryPlanComparisonSummary& Summary) + { + const int32 TightTrust = DeriveMethodDrillRecoveryPlanTightTrust(Summary); + const int32 BroadTrust = DeriveMethodDrillRecoveryPlanBroadTrust(Summary); + return Summary.BroadPlanSourceCount > 0 + && BroadTrust > 0 + && BroadTrust > TightTrust; + } + void CollectMethodDrillRecoveryOutcomeIndices( const TArray& Outcomes, TArray& OutIndices) @@ -6208,6 +6240,17 @@ FHyperTwistCoachDashboardQueueRecoveryWeighting UHyperTwistCoachDashboardWidget: HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPacketDashboardBias( MethodDrillRecoveryMemoryHistoryEntries ); + const HyperTwistCoachDashboardWidgetInternal::FMethodDrillRecoveryPlanComparisonSummary + MethodDrillRecoveryPlanComparisonSummary = + HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPlanComparisonSummary( + MethodDrillRecoveryMemoryHistoryEntries + ); + const int32 TightPlanTrust = + HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPlanTightTrust( + MethodDrillRecoveryPlanComparisonSummary); + const int32 BroadPlanTrust = + HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPlanBroadTrust( + MethodDrillRecoveryPlanComparisonSummary); auto ConsumeOutcome = [ &Weighting, @@ -6406,6 +6449,16 @@ FHyperTwistCoachDashboardQueueRecoveryWeighting UHyperTwistCoachDashboardWidget: Weighting.MethodDrillLaunchBiasCount += MethodDrillRecoveryPacketBias.LaunchRecoveryBias; Weighting.MethodDrillPromoteBiasCount += MethodDrillRecoveryPacketBias.PromoteRecoveryBias; } + if (HyperTwistCoachDashboardWidgetInternal::PrefersMethodDrillRecoveryPlanTightContinuation( + MethodDrillRecoveryPlanComparisonSummary)) + { + Weighting.MethodDrillLaunchBiasCount += FMath::Clamp(TightPlanTrust, 1, 3); + } + else if (HyperTwistCoachDashboardWidgetInternal::PrefersMethodDrillRecoveryPlanBroadRedirect( + MethodDrillRecoveryPlanComparisonSummary)) + { + Weighting.MethodDrillPromoteBiasCount += FMath::Clamp(BroadPlanTrust, 1, 3); + } if (CachedCoachPanelState.PreferredGuidanceSourceLabel == TEXT("coach-memory-method-drill-follow-up-strong")) { @@ -8218,6 +8271,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() bool bHandoffRecommendationUsedMethodDrillWeighting = false; bool bHandoffRecommendationUsedMethodDrillRecoveryMemory = false; bool bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = false; + bool bHandoffRecommendationUsedPlanComparisonHistory = false; bool bHandoffRecommendationUsedStrongRetainedMethodDrillRecoveryPosture = false; bool bHandoffRecommendationUsedWeakRetainedMethodDrillRecoveryPosture = false; const HyperTwistCoachDashboardWidgetInternal::EMethodDrillRecoveryMemoryBias @@ -8250,6 +8304,18 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPlanComparisonSummary( MethodDrillRecoveryMemoryHistoryEntries ); + const int32 MethodDrillRecoveryPlanTightTrust = + HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPlanTightTrust( + MethodDrillRecoveryPlanComparisonSummary); + const int32 MethodDrillRecoveryPlanBroadTrust = + HyperTwistCoachDashboardWidgetInternal::DeriveMethodDrillRecoveryPlanBroadTrust( + MethodDrillRecoveryPlanComparisonSummary); + const bool bPlanComparisonPrefersTightContinuation = + HyperTwistCoachDashboardWidgetInternal::PrefersMethodDrillRecoveryPlanTightContinuation( + MethodDrillRecoveryPlanComparisonSummary); + const bool bPlanComparisonPrefersBroadRedirect = + HyperTwistCoachDashboardWidgetInternal::PrefersMethodDrillRecoveryPlanBroadRedirect( + MethodDrillRecoveryPlanComparisonSummary); const HyperTwistCoachDashboardWidgetInternal::EMethodDrillRecoveryMemoryBias EffectiveMethodDrillRecoveryMemoryHandoffBias = RetainedMethodDrillRecoveryMemoryHandoffBias @@ -8375,6 +8441,38 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() bHandoffRecommendationUsedDeferredOverflowHistory = true; bHandoffRecommendationUsedMethodDrillWeighting = true; } + else if (bPlanComparisonPrefersTightContinuation && bPacketPrefersQueueContinuation) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersTightContinuation && bPacketPrefersFollowUpContinuation) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::FollowUp; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersTightContinuation && bFollowUpReadyForHandoff) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::FollowUp; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersTightContinuation + && bQueueReadyForHandoff + && bQueueLooksFollowUpOrRecovery) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } else if (bPacketPrefersQueueContinuation) { HandoffRecommendationKind = @@ -8425,7 +8523,39 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() && (bFollowUpReadyForHandoff || (bQueueReadyForHandoff && bQueueLooksFollowUpOrRecovery))) { - if (bPacketPrefersQueueContinuation) + if (bPlanComparisonPrefersTightContinuation && bPacketPrefersQueueContinuation) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersTightContinuation && bPacketPrefersFollowUpContinuation) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::FollowUp; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersTightContinuation && bFollowUpReadyForHandoff) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::FollowUp; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersTightContinuation + && bQueueReadyForHandoff + && bQueueLooksFollowUpOrRecovery) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPacketPrefersQueueContinuation) { HandoffRecommendationKind = HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; @@ -8486,6 +8616,38 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() bHandoffRecommendationUsedDeferredOverflowHistory = true; bHandoffRecommendationUsedMethodDrillWeighting = true; } + else if (bPlanComparisonPrefersBroadRedirect && bPacketPrefersRecommendedRedirect) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Recommended; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersBroadRedirect && bPacketPrefersQueueRedirect) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersBroadRedirect && bRecommendedReadyForHandoff) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Recommended; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersBroadRedirect + && bQueueReadyForHandoff + && bQueueLooksRecommendedOrPrimary) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillWeighting = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } else if (bPacketPrefersRecommendedRedirect) { HandoffRecommendationKind = @@ -8536,7 +8698,39 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() && (bRecommendedReadyForHandoff || (bQueueReadyForHandoff && bQueueLooksRecommendedOrPrimary))) { - if (bPacketPrefersRecommendedRedirect) + if (bPlanComparisonPrefersBroadRedirect && bPacketPrefersRecommendedRedirect) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Recommended; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersBroadRedirect && bPacketPrefersQueueRedirect) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedMethodDrillRecoveryPacketHistory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersBroadRedirect && bRecommendedReadyForHandoff) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Recommended; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPlanComparisonPrefersBroadRedirect + && bQueueReadyForHandoff + && bQueueLooksRecommendedOrPrimary) + { + HandoffRecommendationKind = + HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Queue; + bHandoffRecommendationUsedMethodDrillRecoveryMemory = true; + bHandoffRecommendationUsedPlanComparisonHistory = true; + } + else if (bPacketPrefersRecommendedRedirect) { HandoffRecommendationKind = HyperTwistCoachDashboardWidgetInternal::EHandoffRecommendationKind::Recommended; @@ -9012,6 +9206,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() *HyperTwistCoachDashboardWidgetInternal::DescribeMethodDrillRecoveryPlanComparisonPreference( MethodDrillRecoveryPlanComparisonSummary) ); + if (bHandoffRecommendationUsedPlanComparisonHistory) + { + CoachHandoffRecommendationDetailLine += + bPlanComparisonPrefersTightContinuation + ? TEXT(" | Retained plan-alignment history directly tipped this handoff toward trusted tight continuation.") + : TEXT(" | Retained plan-alignment history directly tipped this handoff back toward trusted broad redirect."); + } CoachHandoffRecommendationDetailLine += FString::Printf( TEXT(" | strong posture q/f/r %d/%d/%d, weak posture q/f/r %d/%d/%d"), HandoffHistoryBias.StrongRetainedMethodDrillQueueAcceptedDeltaCount, @@ -9314,6 +9515,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() QueueRecoveryWeighting.MethodDrillUpstreamWeakCount, QueueRecoveryWeighting.MethodDrillUpstreamAverageOutcomeScore ); + const bool bQueueRecoveryUsedPlanComparisonHistory = + (QueueRecoveryWeighting.PreferredActionKind + == FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery + && bPlanComparisonPrefersTightContinuation) + || (QueueRecoveryWeighting.PreferredActionKind + == FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::PromoteDeferred + && bPlanComparisonPrefersBroadRedirect); const FHyperTwistCoachSignal* QueueDeferredFirstSuppressionSignal = HyperTwistCoachDashboardWidgetInternal::FindCoachSignalById( CachedCoachSignals, @@ -9356,6 +9564,11 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() >= MethodDrillRecoveryPacketQueueBias.PromoteRecoveryBias ? TEXT(" | Retained drill-recovery packet history is reinforcing launch recovery.") : TEXT(" | Retained drill-recovery packet history is reinforcing promote-deferred recovery.")) + : (bQueueRecoveryUsedPlanComparisonHistory + ? (QueueRecoveryWeighting.PreferredActionKind + == FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery + ? TEXT(" | Retained plan-alignment history is reinforcing trusted tight continuation recovery.") + : TEXT(" | Retained plan-alignment history is reinforcing trusted broad redirect recovery.")) : (QueueRecoveryWeighting.bHasMethodDrillMemorySignal ? (QueueRecoveryWeighting.PreferredActionKind == FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery @@ -9371,14 +9584,14 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() == FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery ? TEXT(" | Drill-driven accepted handoff history is reinforcing launch recovery.") : TEXT(" | Drill-driven accepted handoff history is present, but promote-deferred recovery still holds.")) - : TEXT("")))); + : TEXT(""))))); const bool bHasQueueRecoveryFriction = CachedCoachSchedulePolicySummary.bHasBlockedFollowUpDeferrals || CachedCoachSchedulePolicySummary.bHasArchiveAwareDeferrals || CachedCoachSchedulePolicySummary.bNeedsManualRescheduleReview || CachedCoachQueueExecutionSummary.bHasOutstandingDeferredWork || CachedCoachQueueExecutionSummary.bHasCompletionGap; - const FString QueueRecoveryStatusLine = bQueueRecoveryMemorySource + FString QueueRecoveryStatusLine = bQueueRecoveryMemorySource ? FString::Printf( TEXT("Recovery: %s lane | Source: %s | Action: %s | Mode: %s | Selection: %s | Upstream: %s | Learned: %s | Stance: %s%s%s"), *QueueRecoveryLaneLabel, @@ -9429,7 +9642,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() ? TEXT("no signal detail") : *QueueDeferredFirstSuppressionSignal->Detail) : TEXT(""); - const FString QueueRecoveryDetailLine = FString::Printf( + FString QueueRecoveryDetailLine = FString::Printf( TEXT("Deferred events %d | Promoted %d | Manual %d | Pressure %.2f | Dominant reason: %s | Follow-up deferrals: %s | Archive-aware deferrals: %s | Completion gap: %s | Upstream action source: %s%s || Learned promote %d/%d reduced, %d failed, avg delta %.2f | launch %d/%d reduced, %d failed, avg delta %.2f | deferred-first promote/launch reduced %d/%d over %d/%d | drill-driven outcome promote/launch reduced %d/%d over %d/%d | retained strong-launch %d/%d, weak-promote %d/%d | drill-driven bias promote/launch %d/%d | packet history queue/follow-up/recommended %d/%d/%d | packet-plan posture tight/broad %d/%d | plan-source tight aligned/diverged %d/%d | broad aligned/diverged %d/%d | plan preferred: %s | packet bias promote/launch %d/%d | upstream drill recovery strong/weak/history %d/%d/%d avg %.1f | retained drill-recovery stance: %s"), CachedCoachQueueExecutionSummary.DeferredEventCount, CachedCoachQueueExecutionSummary.PromotedEventCount, @@ -9485,6 +9698,18 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() *HyperTwistCoachDashboardWidgetInternal::DescribeMethodDrillRecoveryMemoryBias( QueueRecoveryMethodDrillMemoryBias) ); + if (bQueueRecoveryUsedPlanComparisonHistory) + { + QueueRecoveryDetailLine += FString::Printf( + TEXT(" | plan-alignment trust tight/broad %d/%d is actively tipping %s"), + MethodDrillRecoveryPlanTightTrust, + MethodDrillRecoveryPlanBroadTrust, + QueueRecoveryWeighting.PreferredActionKind + == FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery + ? TEXT("trusted tight continuation recovery") + : TEXT("trusted broad redirect recovery") + ); + } RecordMethodDrillRecoveryMemoryHistorySnapshot( QueueRecoveryWeighting, QueueRecoveryStatusLine,