Retain deferred-first dashboard learning

This commit is contained in:
axiomlogicnexus 2026-04-28 03:22:28 +02:00
parent bbd8e4a1f9
commit af9dc0c2eb
2 changed files with 97 additions and 11 deletions

View file

@ -39,6 +39,9 @@ namespace HyperTwistCoachDashboardWidgetInternal
int32 QueueRecommendationCount = 0;
int32 FollowUpRecommendationCount = 0;
int32 RecommendedRecommendationCount = 0;
int32 DeferredFirstQueueRecommendationCount = 0;
int32 DeferredFirstFollowUpRecommendationCount = 0;
int32 DeferredFirstRecommendedRecommendationCount = 0;
int32 QueueScore = 0;
int32 FollowUpScore = 0;
int32 RecommendedScore = 0;
@ -47,6 +50,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
bool bHasAcceptedSignal = false;
bool bHasRecommendationSignal = false;
bool bHasDeferredOverflowAcceptedSignal = false;
bool bHasDeferredFirstSuppressionRecommendationSignal = false;
bool bHasSignal = false;
};
@ -487,18 +491,36 @@ namespace HyperTwistCoachDashboardWidgetInternal
++Bias.QueueRecommendationCount;
++Bias.QueueScore;
Bias.bHasRecommendationSignal = true;
if (Entry.bUsedDeferredFirstSuppressionSignal)
{
++Bias.DeferredFirstQueueRecommendationCount;
Bias.QueueScore += 3;
Bias.bHasDeferredFirstSuppressionRecommendationSignal = true;
}
}
else if (Entry.RecommendedHandoffKindLabel.Equals(TEXT("follow-up"), ESearchCase::IgnoreCase))
{
++Bias.FollowUpRecommendationCount;
++Bias.FollowUpScore;
Bias.bHasRecommendationSignal = true;
if (Entry.bUsedDeferredFirstSuppressionSignal)
{
++Bias.DeferredFirstFollowUpRecommendationCount;
Bias.FollowUpScore += 4;
Bias.bHasDeferredFirstSuppressionRecommendationSignal = true;
}
}
else if (Entry.RecommendedHandoffKindLabel.Equals(TEXT("recommended"), ESearchCase::IgnoreCase))
{
++Bias.RecommendedRecommendationCount;
++Bias.RecommendedScore;
Bias.bHasRecommendationSignal = true;
if (Entry.bUsedDeferredFirstSuppressionSignal)
{
++Bias.DeferredFirstRecommendedRecommendationCount;
++Bias.RecommendedScore;
Bias.bHasDeferredFirstSuppressionRecommendationSignal = true;
}
}
PreviousEntry = Entry;
@ -744,7 +766,9 @@ bool UHyperTwistCoachDashboardWidget::ApplyQueueRecoveryPosture()
BeforeDeferredEventCount,
bBeforeBlockedFollowUp,
bBeforeOutstandingDeferred,
bBeforeCompletionGap
bBeforeCompletionGap,
bHasDeferredFirstSuppressionSignal,
bPrefersFollowUp
](
const TCHAR* AppliedActionLabel,
const FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind ActionKind,
@ -759,6 +783,7 @@ bool UHyperTwistCoachDashboardWidget::ApplyQueueRecoveryPosture()
bBeforeBlockedFollowUp,
bBeforeOutstandingDeferred,
bBeforeCompletionGap,
bHasDeferredFirstSuppressionSignal && bPrefersFollowUp,
bSucceeded
);
UpdateDashboardPresentation();
@ -4175,9 +4200,18 @@ FHyperTwistCoachDashboardQueueRecoveryWeighting UHyperTwistCoachDashboardWidget:
case FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::PromoteDeferred:
++Weighting.PromoteCount;
PromoteDeltaAccumulator += PressureDelta;
if (Outcome.bUsedDeferredFirstSuppressionSignal)
{
++Weighting.DeferredFirstPromoteCount;
Weighting.bHasDeferredFirstSignal = true;
}
if (Outcome.bReducedFriction)
{
++Weighting.PromoteReducedCount;
if (Outcome.bUsedDeferredFirstSuppressionSignal)
{
++Weighting.DeferredFirstPromoteReducedCount;
}
}
if (!Outcome.bSucceeded)
{
@ -4187,9 +4221,18 @@ FHyperTwistCoachDashboardQueueRecoveryWeighting UHyperTwistCoachDashboardWidget:
case FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery:
++Weighting.LaunchCount;
LaunchDeltaAccumulator += PressureDelta;
if (Outcome.bUsedDeferredFirstSuppressionSignal)
{
++Weighting.DeferredFirstLaunchCount;
Weighting.bHasDeferredFirstSignal = true;
}
if (Outcome.bReducedFriction)
{
++Weighting.LaunchReducedCount;
if (Outcome.bUsedDeferredFirstSuppressionSignal)
{
++Weighting.DeferredFirstLaunchReducedCount;
}
}
if (!Outcome.bSucceeded)
{
@ -4261,13 +4304,31 @@ FHyperTwistCoachDashboardQueueRecoveryWeighting UHyperTwistCoachDashboardWidget:
Weighting.LaunchFailureCount,
Weighting.LaunchAveragePressureDelta
);
const float DeferredFirstPromoteScore =
static_cast<float>(Weighting.DeferredFirstPromoteReducedCount) * 3.0f
+ static_cast<float>(
FMath::Max(
Weighting.DeferredFirstPromoteCount - Weighting.DeferredFirstPromoteReducedCount,
0))
* 0.5f;
const float DeferredFirstLaunchScore =
static_cast<float>(Weighting.DeferredFirstLaunchReducedCount) * 3.0f
+ static_cast<float>(
FMath::Max(
Weighting.DeferredFirstLaunchCount - Weighting.DeferredFirstLaunchReducedCount,
0))
* 0.5f;
const float AdjustedPromoteScore =
PromoteScore + (Weighting.bHasDeferredFirstSignal ? DeferredFirstPromoteScore * 1.5f : 0.0f);
const float AdjustedLaunchScore =
LaunchScore + (Weighting.bHasDeferredFirstSignal ? DeferredFirstLaunchScore * 0.75f : 0.0f);
if (PromoteScore > LaunchScore)
if (AdjustedPromoteScore > AdjustedLaunchScore)
{
Weighting.PreferredActionKind =
FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::PromoteDeferred;
}
else if (LaunchScore > PromoteScore)
else if (AdjustedLaunchScore > AdjustedPromoteScore)
{
Weighting.PreferredActionKind =
FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::LaunchRecovery;
@ -4434,6 +4495,7 @@ void UHyperTwistCoachDashboardWidget::RecordQueueRecoveryOutcome(
const bool bBeforeBlockedFollowUp,
const bool bBeforeOutstandingDeferred,
const bool bBeforeCompletionGap,
const bool bUsedDeferredFirstSuppressionSignal,
const bool bSucceeded)
{
QueueRecoveryOutcome.RecordedAtUtc = FDateTime::UtcNow().ToIso8601();
@ -4466,6 +4528,8 @@ void UHyperTwistCoachDashboardWidget::RecordQueueRecoveryOutcome(
|| QueueRecoveryOutcome.bAfterOutstandingDeferred != QueueRecoveryOutcome.bBeforeOutstandingDeferred
|| QueueRecoveryOutcome.bAfterCompletionGap != QueueRecoveryOutcome.bBeforeCompletionGap
);
QueueRecoveryOutcome.bUsedDeferredFirstSuppressionSignal =
bUsedDeferredFirstSuppressionSignal;
bHasQueueRecoveryOutcome = QueueRecoveryOutcome.IsStructurallyValid();
if (bHasQueueRecoveryOutcome)
{
@ -4488,7 +4552,8 @@ void UHyperTwistCoachDashboardWidget::RecordCoachHandoffHistorySnapshot(
const int32 ClosureSuppressionBias,
const bool bQueueReady,
const bool bFollowUpReady,
const bool bRecommendedReady)
const bool bRecommendedReady,
const bool bUsedDeferredFirstSuppressionSignal)
{
FHyperTwistCoachDashboardHandoffHistoryEntry Entry;
Entry.RecordedAtUtc = FDateTime::UtcNow().ToIso8601();
@ -4519,6 +4584,7 @@ void UHyperTwistCoachDashboardWidget::RecordCoachHandoffHistorySnapshot(
Entry.bQueueReady = bQueueReady;
Entry.bFollowUpReady = bFollowUpReady;
Entry.bRecommendedReady = bRecommendedReady;
Entry.bUsedDeferredFirstSuppressionSignal = bUsedDeferredFirstSuppressionSignal;
if (!Entry.IsStructurallyValid())
{
return;
@ -4557,7 +4623,9 @@ void UHyperTwistCoachDashboardWidget::RecordCoachHandoffHistorySnapshot(
== Entry.ClosureSuppressionBias
&& HandoffHistoryEntries.Last().bQueueReady == Entry.bQueueReady
&& HandoffHistoryEntries.Last().bFollowUpReady == Entry.bFollowUpReady
&& HandoffHistoryEntries.Last().bRecommendedReady == Entry.bRecommendedReady;
&& HandoffHistoryEntries.Last().bRecommendedReady == Entry.bRecommendedReady
&& HandoffHistoryEntries.Last().bUsedDeferredFirstSuppressionSignal
== Entry.bUsedDeferredFirstSuppressionSignal;
if (bMatchesLastEntry)
{
return;
@ -5262,7 +5330,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
CoachHandoffRecommendationDetailLine = FString::Printf(
TEXT("Closure continuation bias %d | Closure suppression bias %d | Queue ready: %s | Follow-up ready: %s | Recommended ready: %s | Preferred lane: %s | Memory source: %s%s%s%s%s | Launch bias: %s from %s | broadened/tightened history %d/%d | deferred tightened launches %d | deferred launch cases %d%s | Handoff history preferred: %s | accepted q/f/r %d/%d/%d | deferred-overflow accepted q/f/r %d/%d/%d | recommended q/f/r %d/%d/%d"),
TEXT("Closure continuation bias %d | Closure suppression bias %d | Queue ready: %s | Follow-up ready: %s | Recommended ready: %s | Preferred lane: %s | Memory source: %s%s%s%s%s | Launch bias: %s from %s | broadened/tightened history %d/%d | deferred tightened launches %d | deferred launch cases %d%s | Handoff history preferred: %s | accepted q/f/r %d/%d/%d | deferred-overflow accepted q/f/r %d/%d/%d | deferred-first recommendation q/f/r %d/%d/%d | recommended q/f/r %d/%d/%d"),
HandoffClosureBias.ContinuationBias,
HandoffClosureBias.SuppressionBias,
bQueueReadyForHandoff ? TEXT("yes") : TEXT("no"),
@ -5305,6 +5373,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
HandoffHistoryBias.DeferredOverflowQueueAcceptedDeltaCount,
HandoffHistoryBias.DeferredOverflowFollowUpAcceptedDeltaCount,
HandoffHistoryBias.DeferredOverflowRecommendedAcceptedDeltaCount,
HandoffHistoryBias.DeferredFirstQueueRecommendationCount,
HandoffHistoryBias.DeferredFirstFollowUpRecommendationCount,
HandoffHistoryBias.DeferredFirstRecommendedRecommendationCount,
HandoffHistoryBias.QueueRecommendationCount,
HandoffHistoryBias.FollowUpRecommendationCount,
HandoffHistoryBias.RecommendedRecommendationCount
@ -5320,7 +5391,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
HandoffClosureBias.SuppressionBias,
bQueueReadyForHandoff,
bFollowUpReadyForHandoff,
bRecommendedReadyForHandoff
bRecommendedReadyForHandoff,
bHandoffRecommendationUsedDeferredFirstSuppressionSignal
);
FString QueuedRunLabel = CachedCoachPanelState.NextQueueSourceLabel.IsEmpty()
? TEXT("Start Queue")
@ -5366,13 +5438,14 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
const FString HandoffHistoryDetailLine =
SelectedHandoffHistoryEntry != nullptr
? FString::Printf(
TEXT("Accepted queued/follow-up/recommended: %d/%d/%d | deferred-overflow queued/follow-up/recommended: %d/%d/%d | queue source: %s | preferred lane: %s | memory source: %s | recovery action: %s | recovery source: %s | closure continuation bias %d | closure suppression bias %d | readiness queue/follow-up/recommended: %s/%s/%s || %s"),
TEXT("Accepted queued/follow-up/recommended: %d/%d/%d | deferred-overflow queued/follow-up/recommended: %d/%d/%d | deferred-first suppression recommendation used: %s | queue source: %s | preferred lane: %s | memory source: %s | recovery action: %s | recovery source: %s | closure continuation bias %d | closure suppression bias %d | readiness queue/follow-up/recommended: %s/%s/%s || %s"),
SelectedHandoffHistoryEntry->AcceptedQueuedHandoffCount,
SelectedHandoffHistoryEntry->AcceptedFollowUpHandoffCount,
SelectedHandoffHistoryEntry->AcceptedRecommendedHandoffCount,
SelectedHandoffHistoryEntry->AcceptedDeferredOverflowQueuedHandoffCount,
SelectedHandoffHistoryEntry->AcceptedDeferredOverflowFollowUpHandoffCount,
SelectedHandoffHistoryEntry->AcceptedDeferredOverflowRecommendedHandoffCount,
SelectedHandoffHistoryEntry->bUsedDeferredFirstSuppressionSignal ? TEXT("yes") : TEXT("no"),
SelectedHandoffHistoryEntry->QueueSourceLabel.IsEmpty()
? TEXT("n/a")
: *SelectedHandoffHistoryEntry->QueueSourceLabel,
@ -5624,7 +5697,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
: *QueueDeferredFirstSuppressionSignal->Detail)
: TEXT("");
const 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"),
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"),
CachedCoachQueueExecutionSummary.DeferredEventCount,
CachedCoachQueueExecutionSummary.PromotedEventCount,
CachedCoachQueueExecutionSummary.ManualRescheduleEventCount,
@ -5644,7 +5717,11 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
QueueRecoveryWeighting.LaunchReducedCount,
QueueRecoveryWeighting.LaunchCount,
QueueRecoveryWeighting.LaunchFailureCount,
QueueRecoveryWeighting.LaunchAveragePressureDelta
QueueRecoveryWeighting.LaunchAveragePressureDelta,
QueueRecoveryWeighting.DeferredFirstPromoteReducedCount,
QueueRecoveryWeighting.DeferredFirstLaunchReducedCount,
QueueRecoveryWeighting.DeferredFirstPromoteCount,
QueueRecoveryWeighting.DeferredFirstLaunchCount
);
const bool bHasPrimaryQueueSuppression =
CachedCoachSessionQueueSummary.bSuppressedPrimaryQueueCreation

View file

@ -147,6 +147,7 @@ struct FHyperTwistCoachDashboardQueueRecoveryOutcome
bool bSucceeded = false;
bool bReducedFriction = false;
bool bShiftedFriction = false;
bool bUsedDeferredFirstSuppressionSignal = false;
bool IsStructurallyValid() const
{
@ -162,11 +163,16 @@ struct FHyperTwistCoachDashboardQueueRecoveryWeighting
int32 LaunchCount = 0;
int32 LaunchReducedCount = 0;
int32 LaunchFailureCount = 0;
int32 DeferredFirstPromoteCount = 0;
int32 DeferredFirstPromoteReducedCount = 0;
int32 DeferredFirstLaunchCount = 0;
int32 DeferredFirstLaunchReducedCount = 0;
float PromoteAveragePressureDelta = 0.0f;
float LaunchAveragePressureDelta = 0.0f;
FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind PreferredActionKind =
FHyperTwistCoachDashboardQueueRecoveryOutcome::EActionKind::None;
bool bHasSignal = false;
bool bHasDeferredFirstSignal = false;
bool IsStructurallyValid() const
{
@ -251,6 +257,7 @@ struct FHyperTwistCoachDashboardHandoffHistoryEntry
bool bQueueReady = false;
bool bFollowUpReady = false;
bool bRecommendedReady = false;
bool bUsedDeferredFirstSuppressionSignal = false;
bool IsStructurallyValid() const
{
@ -1120,6 +1127,7 @@ private:
bool bBeforeBlockedFollowUp,
bool bBeforeOutstandingDeferred,
bool bBeforeCompletionGap,
bool bUsedDeferredFirstSuppressionSignal,
bool bSucceeded
);
void RecordCoachHandoffHistorySnapshot(
@ -1131,7 +1139,8 @@ private:
int32 ClosureSuppressionBias,
bool bQueueReady,
bool bFollowUpReady,
bool bRecommendedReady
bool bRecommendedReady,
bool bUsedDeferredFirstSuppressionSignal
);
void RecordQueueSuppressionSnapshot();
void RecordClosureRecoverySnapshot();