Expose dashboard live guidance inspect surfaces
This commit is contained in:
parent
6246f41e5c
commit
db016a0789
5 changed files with 1027 additions and 2 deletions
|
|
@ -8509,6 +8509,603 @@ UHyperTwistCoachDashboardWidget::GetSelectedTemplateLaunchHistoryInspectSurface(
|
|||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardGuidanceComparisonInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceComparisonInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardGuidanceComparisonInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Guidance comparison");
|
||||
Surface.bClosedLoopIdleActionability = IsCoachLoopActionabilityClosed();
|
||||
|
||||
const auto BuildLaneLabel =
|
||||
[](const EHyperTwistCoachDashboardGuidancePreviewLane Lane) -> FString
|
||||
{
|
||||
return Lane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
|
||||
? TEXT("recommended")
|
||||
: (Lane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
|
||||
? TEXT("follow-up")
|
||||
: TEXT("none"));
|
||||
};
|
||||
const auto BuildDeckLabel =
|
||||
[](const FHyperTwistTrainingDeck* Deck) -> FString
|
||||
{
|
||||
if (Deck == nullptr || !Deck->IsStructurallyValid())
|
||||
{
|
||||
return TEXT("n/a");
|
||||
}
|
||||
|
||||
return Deck->Title.IsEmpty() ? Deck->DeckId : Deck->Title;
|
||||
};
|
||||
|
||||
const bool bHasCurrentRunRecap = CachedRunState.Session.IsStructurallyValid()
|
||||
&& (CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|
||||
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedRunRecap = bHasCurrentRunRecap
|
||||
? &CachedRunSummary
|
||||
: (bHasRetainedRunRecap ? &RetainedRunRecapSummary : nullptr);
|
||||
const FHyperTwistTrainingDeck* DisplayedRunRecapDeck = bHasCurrentRunRecap
|
||||
? &CachedRunState.ActiveDeck
|
||||
: (bHasRetainedRunRecap ? &RetainedRunRecapDeck : nullptr);
|
||||
const EHyperTwistTrainingDeliveryMode DisplayedRunRecapMode = bHasCurrentRunRecap
|
||||
? CachedRunState.Session.Mode
|
||||
: RetainedRunRecapMode;
|
||||
const bool bHasDisplayedRunRecap = DisplayedRunRecap != nullptr
|
||||
&& !DisplayedRunRecap->TrainingSessionId.IsEmpty();
|
||||
Surface.bHasDisplayedRunRecap = bHasDisplayedRunRecap;
|
||||
Surface.RunRecapSourceLabel = bHasDisplayedRunRecap
|
||||
? (bHasCurrentRunRecap ? TEXT("current run") : TEXT("last completed run"))
|
||||
: TEXT("none");
|
||||
Surface.TrainingSessionId = bHasDisplayedRunRecap
|
||||
? DisplayedRunRecap->TrainingSessionId
|
||||
: TEXT("n/a");
|
||||
Surface.ActualDeckLabel = BuildDeckLabel(DisplayedRunRecapDeck);
|
||||
Surface.ActualModeLabel =
|
||||
bHasDisplayedRunRecap
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecapMode)
|
||||
: TEXT("n/a");
|
||||
Surface.ActualSelectionLabel =
|
||||
DisplayedRunRecapDeck != nullptr && DisplayedRunRecapDeck->IsStructurallyValid()
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedRunRecapDeck->SelectionPolicy)
|
||||
: TEXT("n/a");
|
||||
Surface.LastCaseId =
|
||||
bHasDisplayedRunRecap && !DisplayedRunRecap->LastCaseId.IsEmpty()
|
||||
? DisplayedRunRecap->LastCaseId
|
||||
: TEXT("n/a");
|
||||
Surface.CompletedAttemptCount =
|
||||
bHasDisplayedRunRecap ? DisplayedRunRecap->CompletedAttemptCount : 0;
|
||||
Surface.FailureCount = bHasDisplayedRunRecap ? DisplayedRunRecap->FailureCount : 0;
|
||||
Surface.TimeoutCount = bHasDisplayedRunRecap ? DisplayedRunRecap->TimeoutCount : 0;
|
||||
Surface.DNFCount = bHasDisplayedRunRecap ? DisplayedRunRecap->DNFCount : 0;
|
||||
Surface.TotalMistakes = bHasDisplayedRunRecap ? DisplayedRunRecap->TotalMistakes : 0;
|
||||
Surface.SuccessRate = bHasDisplayedRunRecap ? DisplayedRunRecap->SuccessRate : 0.0f;
|
||||
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedGuidanceComparisonRunRecap = nullptr;
|
||||
const FHyperTwistCoachBrief* DisplayedGuidanceComparisonBrief = nullptr;
|
||||
const FHyperTwistTrainingDeck* DisplayedGuidanceComparisonDeck = nullptr;
|
||||
FString DisplayedGuidanceComparisonSelectedCaseId;
|
||||
bool bDisplayedGuidanceComparisonSingleCase = false;
|
||||
Surface.bHasComparisonContext = ResolveDisplayedGuidanceComparisonContext(
|
||||
DisplayedGuidanceComparisonRunRecap,
|
||||
DisplayedGuidanceComparisonBrief,
|
||||
DisplayedGuidanceComparisonDeck,
|
||||
DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bDisplayedGuidanceComparisonSingleCase);
|
||||
Surface.bHasDisplayedGuidanceBrief = DisplayedGuidanceComparisonBrief != nullptr;
|
||||
Surface.bHasDisplayedGuidanceDeck =
|
||||
DisplayedGuidanceComparisonDeck != nullptr
|
||||
&& DisplayedGuidanceComparisonDeck->IsStructurallyValid();
|
||||
Surface.bSingleCaseScope = bDisplayedGuidanceComparisonSingleCase;
|
||||
Surface.ScopeLabel = Surface.bHasComparisonContext
|
||||
? (Surface.bSingleCaseScope ? TEXT("selected case") : TEXT("full preview deck"))
|
||||
: TEXT("none");
|
||||
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane DisplayedGuidanceComparisonLane =
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
if (DisplayedGuidanceComparisonBrief == &ActiveGuidanceLaunchBrief)
|
||||
{
|
||||
DisplayedGuidanceComparisonLane = ActiveGuidanceLaunchLane;
|
||||
}
|
||||
else if (DisplayedGuidanceComparisonBrief == &RetainedGuidanceComparisonBrief)
|
||||
{
|
||||
DisplayedGuidanceComparisonLane = RetainedGuidanceComparisonLane;
|
||||
}
|
||||
|
||||
Surface.GuidanceLaneLabel = BuildLaneLabel(DisplayedGuidanceComparisonLane);
|
||||
Surface.BriefHeadline =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
&& !DisplayedGuidanceComparisonBrief->Headline.IsEmpty()
|
||||
? DisplayedGuidanceComparisonBrief->Headline
|
||||
: TEXT("n/a");
|
||||
Surface.PrimaryActionLabel =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
&& !DisplayedGuidanceComparisonBrief->PrimaryActionLabel.IsEmpty()
|
||||
? DisplayedGuidanceComparisonBrief->PrimaryActionLabel
|
||||
: TEXT("n/a");
|
||||
Surface.PreviewDeckLabel = BuildDeckLabel(DisplayedGuidanceComparisonDeck);
|
||||
Surface.ExpectedModeLabel =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedGuidanceComparisonBrief->SuggestedMode)
|
||||
: TEXT("n/a");
|
||||
Surface.ExpectedSelectionLabel =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedGuidanceComparisonBrief->SuggestedSelectionPolicy)
|
||||
: TEXT("n/a");
|
||||
Surface.FocusLaneLabel =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedGuidanceComparisonBrief->FocusLane)
|
||||
: TEXT("n/a");
|
||||
Surface.SelectedCaseId =
|
||||
!DisplayedGuidanceComparisonSelectedCaseId.IsEmpty()
|
||||
? DisplayedGuidanceComparisonSelectedCaseId
|
||||
: TEXT("n/a");
|
||||
Surface.ExpectedCaseCount =
|
||||
DisplayedGuidanceComparisonDeck != nullptr ? DisplayedGuidanceComparisonDeck->Cases.Num() : 0;
|
||||
Surface.FocusCaseCount =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
? DisplayedGuidanceComparisonBrief->FocusCaseIds.Num()
|
||||
: 0;
|
||||
Surface.bSelectedCaseMatchesLastCase =
|
||||
bHasDisplayedRunRecap
|
||||
&& !DisplayedGuidanceComparisonSelectedCaseId.IsEmpty()
|
||||
&& DisplayedRunRecap->LastCaseId == DisplayedGuidanceComparisonSelectedCaseId;
|
||||
|
||||
Surface.StatusLine = Surface.bHasComparisonContext
|
||||
? FString::Printf(
|
||||
TEXT("Comparison: %s recap vs %s preview | Scope: %s | Focus lane: %s | Expected cases: %d | Completed attempts: %d | Success rate: %.2f"),
|
||||
*Surface.RunRecapSourceLabel,
|
||||
*Surface.GuidanceLaneLabel,
|
||||
Surface.bSingleCaseScope ? TEXT("selected case") : TEXT("full preview deck"),
|
||||
*Surface.FocusLaneLabel,
|
||||
Surface.ExpectedCaseCount,
|
||||
Surface.CompletedAttemptCount,
|
||||
Surface.SuccessRate)
|
||||
: TEXT("Comparison: complete a run launched from previewed guidance to compare the recap against the original coach intent.");
|
||||
Surface.DetailLine = Surface.bHasComparisonContext
|
||||
? FString::Printf(
|
||||
TEXT("Launch brief: %s | Action: %s | Preview deck: %s | Actual deck: %s | Mode expected/actual: %s / %s | Selection expected/actual: %s / %s | Selected case: %s | Last case matched: %s | Focus cases: %d | Last case: %s"),
|
||||
*Surface.BriefHeadline,
|
||||
*Surface.PrimaryActionLabel,
|
||||
*Surface.PreviewDeckLabel,
|
||||
*Surface.ActualDeckLabel,
|
||||
*Surface.ExpectedModeLabel,
|
||||
*Surface.ActualModeLabel,
|
||||
*Surface.ExpectedSelectionLabel,
|
||||
*Surface.ActualSelectionLabel,
|
||||
*Surface.SelectedCaseId,
|
||||
Surface.bSelectedCaseMatchesLastCase ? TEXT("yes") : TEXT("no"),
|
||||
Surface.FocusCaseCount,
|
||||
*Surface.LastCaseId)
|
||||
: TEXT("Comparison detail: no preview-launched recap is currently selected.");
|
||||
if (Surface.bClosedLoopIdleActionability
|
||||
&& !Surface.bHasComparisonContext)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Comparison: retained comparison history remains inspectable, but no preview-launched recap is currently selected in the closed-loop idle state.");
|
||||
Surface.DetailLine =
|
||||
TEXT("Comparison detail: the coach-to-review loop is closed and idle, so no live recommended or follow-up comparison target remains active.");
|
||||
}
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardGuidanceOutcomeInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceOutcomeInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardGuidanceOutcomeInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Guidance outcome");
|
||||
Surface.bClosedLoopIdleActionability = IsCoachLoopActionabilityClosed();
|
||||
|
||||
const auto BuildLaneLabel =
|
||||
[](const EHyperTwistCoachDashboardGuidancePreviewLane Lane) -> FString
|
||||
{
|
||||
return Lane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
|
||||
? TEXT("recommended")
|
||||
: (Lane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
|
||||
? TEXT("follow-up")
|
||||
: TEXT("none"));
|
||||
};
|
||||
const auto BuildDecisionActionLabel =
|
||||
[this](const EHyperTwistCoachDashboardOutcomeAction Action) -> FString
|
||||
{
|
||||
return Action == EHyperTwistCoachDashboardOutcomeAction::None
|
||||
? TEXT("none")
|
||||
: BuildGuidanceOutcomeActionLabel(Action);
|
||||
};
|
||||
|
||||
const bool bHasCurrentRunRecap = CachedRunState.Session.IsStructurallyValid()
|
||||
&& (CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|
||||
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedRunRecap = bHasCurrentRunRecap
|
||||
? &CachedRunSummary
|
||||
: (bHasRetainedRunRecap ? &RetainedRunRecapSummary : nullptr);
|
||||
Surface.bHasDisplayedRunRecap =
|
||||
DisplayedRunRecap != nullptr && !DisplayedRunRecap->TrainingSessionId.IsEmpty();
|
||||
Surface.RunRecapSourceLabel = Surface.bHasDisplayedRunRecap
|
||||
? (bHasCurrentRunRecap ? TEXT("current run") : TEXT("last completed run"))
|
||||
: TEXT("none");
|
||||
Surface.TrainingSessionId = Surface.bHasDisplayedRunRecap
|
||||
? DisplayedRunRecap->TrainingSessionId
|
||||
: TEXT("n/a");
|
||||
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedGuidanceComparisonRunRecap = nullptr;
|
||||
const FHyperTwistCoachBrief* DisplayedGuidanceComparisonBrief = nullptr;
|
||||
const FHyperTwistTrainingDeck* DisplayedGuidanceComparisonDeck = nullptr;
|
||||
FString DisplayedGuidanceComparisonSelectedCaseId;
|
||||
bool bDisplayedGuidanceComparisonSingleCase = false;
|
||||
Surface.bHasComparisonContext = ResolveDisplayedGuidanceComparisonContext(
|
||||
DisplayedGuidanceComparisonRunRecap,
|
||||
DisplayedGuidanceComparisonBrief,
|
||||
DisplayedGuidanceComparisonDeck,
|
||||
DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bDisplayedGuidanceComparisonSingleCase);
|
||||
Surface.bHasDisplayedGuidanceBrief = DisplayedGuidanceComparisonBrief != nullptr;
|
||||
Surface.bHasDisplayedGuidanceDeck =
|
||||
DisplayedGuidanceComparisonDeck != nullptr
|
||||
&& DisplayedGuidanceComparisonDeck->IsStructurallyValid();
|
||||
Surface.bSingleCaseScope = bDisplayedGuidanceComparisonSingleCase;
|
||||
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane DisplayedGuidanceComparisonLane =
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
if (DisplayedGuidanceComparisonBrief == &ActiveGuidanceLaunchBrief)
|
||||
{
|
||||
DisplayedGuidanceComparisonLane = ActiveGuidanceLaunchLane;
|
||||
}
|
||||
else if (DisplayedGuidanceComparisonBrief == &RetainedGuidanceComparisonBrief)
|
||||
{
|
||||
DisplayedGuidanceComparisonLane = RetainedGuidanceComparisonLane;
|
||||
}
|
||||
|
||||
Surface.GuidanceLaneLabel = BuildLaneLabel(DisplayedGuidanceComparisonLane);
|
||||
Surface.ScopeLabel = Surface.bHasComparisonContext
|
||||
? (Surface.bSingleCaseScope ? TEXT("selected case") : TEXT("preview deck"))
|
||||
: TEXT("none");
|
||||
Surface.BriefHeadline =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
&& !DisplayedGuidanceComparisonBrief->Headline.IsEmpty()
|
||||
? DisplayedGuidanceComparisonBrief->Headline
|
||||
: TEXT("n/a");
|
||||
Surface.SelectedCaseId =
|
||||
!DisplayedGuidanceComparisonSelectedCaseId.IsEmpty()
|
||||
? DisplayedGuidanceComparisonSelectedCaseId
|
||||
: TEXT("n/a");
|
||||
Surface.ExpectedCaseCount =
|
||||
DisplayedGuidanceComparisonDeck != nullptr ? DisplayedGuidanceComparisonDeck->Cases.Num() : 0;
|
||||
Surface.CompletedAttemptCount =
|
||||
DisplayedRunRecap != nullptr ? DisplayedRunRecap->CompletedAttemptCount : 0;
|
||||
Surface.NonSuccessCount =
|
||||
DisplayedRunRecap != nullptr
|
||||
? (DisplayedRunRecap->FailureCount
|
||||
+ DisplayedRunRecap->TimeoutCount
|
||||
+ DisplayedRunRecap->DNFCount)
|
||||
: 0;
|
||||
Surface.TotalMistakes = DisplayedRunRecap != nullptr ? DisplayedRunRecap->TotalMistakes : 0;
|
||||
Surface.SuccessRate = DisplayedRunRecap != nullptr ? DisplayedRunRecap->SuccessRate : 0.0f;
|
||||
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: complete a run launched from previewed guidance to derive a repeat, broaden, or redirect verdict.");
|
||||
Surface.DetailLine =
|
||||
TEXT("Outcome detail: no preview-launched recap is currently selected.");
|
||||
if (DisplayedRunRecap != nullptr
|
||||
&& DisplayedGuidanceComparisonBrief != nullptr
|
||||
&& DisplayedGuidanceComparisonDeck != nullptr
|
||||
&& DisplayedRunRecap->CompletedAttemptCount > 0)
|
||||
{
|
||||
if (Surface.bSingleCaseScope)
|
||||
{
|
||||
if (DisplayedRunRecap->SuccessRate >= 0.85f
|
||||
&& DisplayedRunRecap->TimeoutCount == 0
|
||||
&& DisplayedRunRecap->DNFCount == 0
|
||||
&& DisplayedRunRecap->TotalMistakes <= 1)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: broaden guidance. The selected case looks stable enough to expand back to the wider preview deck.");
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Recommendation: move from the single-case launch into the broader %s preview deck or the next coach-directed handoff. Success rate %.2f across %d completed attempts with %d mistakes."),
|
||||
*Surface.GuidanceLaneLabel,
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
DisplayedRunRecap->CompletedAttemptCount,
|
||||
DisplayedRunRecap->TotalMistakes);
|
||||
}
|
||||
else if (DisplayedRunRecap->SuccessRate >= 0.5f)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: stabilize, then broaden. The selected case is moving, but it is not yet clean enough for a wider shift.");
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Recommendation: repeat the selected preview case or a very small scope before broadening. Success rate %.2f with %d non-success outcomes and %d mistakes."),
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
Surface.NonSuccessCount,
|
||||
DisplayedRunRecap->TotalMistakes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: repeat selected focus. The previewed case is still weak enough that broadening would be premature.");
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Recommendation: stay on the selected preview case until the recap is cleaner. Success rate %.2f with %d non-success outcomes and %d mistakes."),
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
Surface.NonSuccessCount,
|
||||
DisplayedRunRecap->TotalMistakes);
|
||||
}
|
||||
}
|
||||
else if (DisplayedRunRecap->SuccessRate >= 0.8f
|
||||
&& Surface.NonSuccessCount <= FMath::Max(1, DisplayedRunRecap->CompletedAttemptCount / 4)
|
||||
&& DisplayedRunRecap->TotalMistakes <= FMath::Max(1, DisplayedRunRecap->CompletedAttemptCount / 2))
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: change guidance. The full preview deck looks stable enough to move on from this exact focus.");
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Recommendation: use follow-up, queued, or recommended coach handoff rather than repeating the same deck. Success rate %.2f across %d completed attempts with %d mistakes."),
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
DisplayedRunRecap->CompletedAttemptCount,
|
||||
DisplayedRunRecap->TotalMistakes);
|
||||
}
|
||||
else if (DisplayedRunRecap->SuccessRate >= 0.55f)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: repeat and stabilize. The deck is moving, but not cleanly enough to abandon this scope.");
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Recommendation: repeat the preview deck or stay near this focus before changing guidance. Success rate %.2f with %d non-success outcomes and %d mistakes."),
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
Surface.NonSuccessCount,
|
||||
DisplayedRunRecap->TotalMistakes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: narrow or redirect guidance. The broad preview scope is still too unstable.");
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Recommendation: narrow back to a smaller focus case set or switch guidance lanes before repeating the full deck. Success rate %.2f with %d non-success outcomes and %d mistakes."),
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
Surface.NonSuccessCount,
|
||||
DisplayedRunRecap->TotalMistakes);
|
||||
}
|
||||
}
|
||||
|
||||
const EHyperTwistCoachDashboardOutcomeAction BaseGuidanceOutcomeAction =
|
||||
DeriveGuidanceOutcomeAction();
|
||||
const FHyperTwistCoachDashboardDecisionWeighting GuidanceDecisionWeighting =
|
||||
BuildGuidanceDecisionWeighting(BaseGuidanceOutcomeAction);
|
||||
const EHyperTwistCoachDashboardOutcomeAction GuidanceOutcomeAction =
|
||||
GuidanceDecisionWeighting.WeightedAction != EHyperTwistCoachDashboardOutcomeAction::None
|
||||
? GuidanceDecisionWeighting.WeightedAction
|
||||
: BaseGuidanceOutcomeAction;
|
||||
Surface.BaseActionLabel = BuildDecisionActionLabel(BaseGuidanceOutcomeAction);
|
||||
Surface.WeightedActionLabel =
|
||||
BuildDecisionActionLabel(GuidanceDecisionWeighting.WeightedAction);
|
||||
Surface.bHasWeightingOverride = GuidanceDecisionWeighting.bHasOverride;
|
||||
Surface.bUsedClosureHistorySignal =
|
||||
GuidanceDecisionWeighting.bUsedClosureHistorySignal;
|
||||
Surface.bUsedDeferredOverflowSignal =
|
||||
GuidanceDecisionWeighting.bUsedDeferredOverflowSignal;
|
||||
if (GuidanceDecisionWeighting.bUsedClosureHistorySignal)
|
||||
{
|
||||
Surface.StatusLine += TEXT(" Closure-recovery history adjusted this recommendation.");
|
||||
}
|
||||
if (GuidanceDecisionWeighting.bUsedDeferredOverflowSignal)
|
||||
{
|
||||
Surface.StatusLine +=
|
||||
TEXT(" Deferred-overflow continuation history adjusted this recommendation.");
|
||||
}
|
||||
|
||||
Surface.bCanRedirectAction =
|
||||
CachedCoachPanelState.bCanStartCoachFollowUpRun
|
||||
|| CachedCoachPanelState.bCanStartQueuedRun
|
||||
|| CachedCoachPanelState.bCanStartCoachRecommendedRun;
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
&& CachedRunState.ActiveDeck.IsStructurallyValid();
|
||||
Surface.bCanApplyAction =
|
||||
GuidanceOutcomeAction != EHyperTwistCoachDashboardOutcomeAction::None
|
||||
&& !bHasLiveAttemptTimer
|
||||
&& (!bHasActiveRun
|
||||
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|
||||
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted)
|
||||
&& (GuidanceOutcomeAction != EHyperTwistCoachDashboardOutcomeAction::RedirectCoachGuidance
|
||||
|| Surface.bCanRedirectAction);
|
||||
Surface.ActionLabel = BuildGuidanceOutcomeActionLabel(GuidanceOutcomeAction);
|
||||
if (Surface.bClosedLoopIdleActionability)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Outcome: retained comparison history remains inspectable, but the coach-to-review loop is closed and idle.");
|
||||
Surface.DetailLine =
|
||||
TEXT("Outcome detail: no live repeat, broaden, or redirect action remains while the closed-loop idle boundary holds.");
|
||||
Surface.ActionLabel = TEXT("Loop Idle");
|
||||
Surface.bCanApplyAction = false;
|
||||
}
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardGuidanceDecisionWeightingInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceDecisionWeightingInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardGuidanceDecisionWeightingInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Decision weighting");
|
||||
Surface.bClosedLoopIdleActionability = IsCoachLoopActionabilityClosed();
|
||||
|
||||
const auto BuildLaneLabel =
|
||||
[](const EHyperTwistCoachDashboardGuidancePreviewLane Lane) -> FString
|
||||
{
|
||||
return Lane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
|
||||
? TEXT("recommended")
|
||||
: (Lane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
|
||||
? TEXT("follow-up")
|
||||
: TEXT("none"));
|
||||
};
|
||||
const auto BuildDecisionActionLabel =
|
||||
[this](const EHyperTwistCoachDashboardOutcomeAction Action) -> FString
|
||||
{
|
||||
return Action == EHyperTwistCoachDashboardOutcomeAction::None
|
||||
? TEXT("none")
|
||||
: BuildGuidanceOutcomeActionLabel(Action);
|
||||
};
|
||||
|
||||
const bool bHasCurrentRunRecap = CachedRunState.Session.IsStructurallyValid()
|
||||
&& (CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|
||||
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedRunRecap = bHasCurrentRunRecap
|
||||
? &CachedRunSummary
|
||||
: (bHasRetainedRunRecap ? &RetainedRunRecapSummary : nullptr);
|
||||
Surface.bHasDisplayedRunRecap =
|
||||
DisplayedRunRecap != nullptr && !DisplayedRunRecap->TrainingSessionId.IsEmpty();
|
||||
Surface.RunRecapSourceLabel = Surface.bHasDisplayedRunRecap
|
||||
? (bHasCurrentRunRecap ? TEXT("current run") : TEXT("last completed run"))
|
||||
: TEXT("none");
|
||||
Surface.TrainingSessionId = Surface.bHasDisplayedRunRecap
|
||||
? DisplayedRunRecap->TrainingSessionId
|
||||
: TEXT("n/a");
|
||||
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedGuidanceComparisonRunRecap = nullptr;
|
||||
const FHyperTwistCoachBrief* DisplayedGuidanceComparisonBrief = nullptr;
|
||||
const FHyperTwistTrainingDeck* DisplayedGuidanceComparisonDeck = nullptr;
|
||||
FString DisplayedGuidanceComparisonSelectedCaseId;
|
||||
bool bDisplayedGuidanceComparisonSingleCase = false;
|
||||
Surface.bHasComparisonContext = ResolveDisplayedGuidanceComparisonContext(
|
||||
DisplayedGuidanceComparisonRunRecap,
|
||||
DisplayedGuidanceComparisonBrief,
|
||||
DisplayedGuidanceComparisonDeck,
|
||||
DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bDisplayedGuidanceComparisonSingleCase);
|
||||
Surface.bHasDisplayedGuidanceBrief = DisplayedGuidanceComparisonBrief != nullptr;
|
||||
Surface.bHasDisplayedGuidanceDeck =
|
||||
DisplayedGuidanceComparisonDeck != nullptr
|
||||
&& DisplayedGuidanceComparisonDeck->IsStructurallyValid();
|
||||
Surface.bSingleCaseScope = bDisplayedGuidanceComparisonSingleCase;
|
||||
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane DisplayedGuidanceComparisonLane =
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
if (DisplayedGuidanceComparisonBrief == &ActiveGuidanceLaunchBrief)
|
||||
{
|
||||
DisplayedGuidanceComparisonLane = ActiveGuidanceLaunchLane;
|
||||
}
|
||||
else if (DisplayedGuidanceComparisonBrief == &RetainedGuidanceComparisonBrief)
|
||||
{
|
||||
DisplayedGuidanceComparisonLane = RetainedGuidanceComparisonLane;
|
||||
}
|
||||
|
||||
Surface.GuidanceLaneLabel = BuildLaneLabel(DisplayedGuidanceComparisonLane);
|
||||
Surface.ScopeLabel = Surface.bHasComparisonContext
|
||||
? (Surface.bSingleCaseScope ? TEXT("selected case") : TEXT("preview deck"))
|
||||
: TEXT("none");
|
||||
Surface.BriefHeadline =
|
||||
DisplayedGuidanceComparisonBrief != nullptr
|
||||
&& !DisplayedGuidanceComparisonBrief->Headline.IsEmpty()
|
||||
? DisplayedGuidanceComparisonBrief->Headline
|
||||
: TEXT("n/a");
|
||||
Surface.SelectedCaseId =
|
||||
!DisplayedGuidanceComparisonSelectedCaseId.IsEmpty()
|
||||
? DisplayedGuidanceComparisonSelectedCaseId
|
||||
: TEXT("n/a");
|
||||
|
||||
const EHyperTwistCoachDashboardOutcomeAction BaseAction = DeriveGuidanceOutcomeAction();
|
||||
const FHyperTwistCoachDashboardDecisionWeighting Weighting =
|
||||
BuildGuidanceDecisionWeighting(BaseAction);
|
||||
const EHyperTwistCoachDashboardOutcomeAction ResolvedAction =
|
||||
Weighting.WeightedAction != EHyperTwistCoachDashboardOutcomeAction::None
|
||||
? Weighting.WeightedAction
|
||||
: BaseAction;
|
||||
Surface.ResolvedActionLabel = BuildGuidanceOutcomeActionLabel(ResolvedAction);
|
||||
Surface.BaseActionLabel = BuildDecisionActionLabel(Weighting.BaseAction);
|
||||
Surface.WeightedActionLabel = BuildDecisionActionLabel(Weighting.WeightedAction);
|
||||
Surface.LastAppliedActionLabel = BuildDecisionActionLabel(Weighting.LastAppliedAction);
|
||||
Surface.MatchingDecisionCount = Weighting.MatchingDecisionCount;
|
||||
Surface.RepeatSelectedCaseCount = Weighting.RepeatSelectedCaseCount;
|
||||
Surface.RepeatPreviewDeckCount = Weighting.RepeatPreviewDeckCount;
|
||||
Surface.BroadenPreviewDeckCount = Weighting.BroadenPreviewDeckCount;
|
||||
Surface.RedirectCoachGuidanceCount = Weighting.RedirectCoachGuidanceCount;
|
||||
Surface.BroadenedLaunchCount = Weighting.BroadenedLaunchCount;
|
||||
Surface.TightenedLaunchCount = Weighting.TightenedLaunchCount;
|
||||
Surface.ClosureContinuationBias = Weighting.ClosureContinuationBias;
|
||||
Surface.ClosureSuppressionBias = Weighting.ClosureSuppressionBias;
|
||||
Surface.DeferredOverflowContinuationBias =
|
||||
Weighting.DeferredOverflowContinuationBias;
|
||||
Surface.DeferredOverflowCaseCount = Weighting.DeferredOverflowCaseCount;
|
||||
Surface.ReliableAlignedTrustedTightPlanOutcomeHistoryCount =
|
||||
Weighting.ReliableAlignedTrustedTightPlanOutcomeHistoryCount;
|
||||
Surface.ReliableAlignedTrustedBroadPlanOutcomeHistoryCount =
|
||||
Weighting.ReliableAlignedTrustedBroadPlanOutcomeHistoryCount;
|
||||
Surface.ReliableAlignedTrustedTightContinuationDecisionCount =
|
||||
Weighting.ReliableAlignedTrustedTightContinuationDecisionCount;
|
||||
Surface.ReliableAlignedTrustedBroadRedirectDecisionCount =
|
||||
Weighting.ReliableAlignedTrustedBroadRedirectDecisionCount;
|
||||
Surface.AverageSuccessRate = Weighting.AverageSuccessRate;
|
||||
Surface.AverageLaunchCaseCount = Weighting.AverageLaunchCaseCount;
|
||||
Surface.BroadenedLaunchAverageSuccessRate =
|
||||
Weighting.BroadenedLaunchAverageSuccessRate;
|
||||
Surface.TightenedLaunchAverageSuccessRate =
|
||||
Weighting.TightenedLaunchAverageSuccessRate;
|
||||
Surface.ReliableAlignedTrustedTightPlanOutcomeAverageScore =
|
||||
Weighting.ReliableAlignedTrustedTightPlanOutcomeAverageScore;
|
||||
Surface.ReliableAlignedTrustedBroadPlanOutcomeAverageScore =
|
||||
Weighting.ReliableAlignedTrustedBroadPlanOutcomeAverageScore;
|
||||
Surface.bHasWeighting = Weighting.IsStructurallyValid();
|
||||
Surface.bHasWeightingOverride = Weighting.bHasOverride;
|
||||
Surface.bUsedClosureHistorySignal = Weighting.bUsedClosureHistorySignal;
|
||||
Surface.bUsedDeferredOverflowSignal = Weighting.bUsedDeferredOverflowSignal;
|
||||
Surface.bUsedReliableAlignedPlanOutcomeSignal =
|
||||
Weighting.bUsedReliableAlignedPlanOutcomeSignal;
|
||||
|
||||
Surface.StatusLine = Weighting.IsStructurallyValid()
|
||||
? FString::Printf(
|
||||
TEXT("Weighting: %d matching decisions | Base: %s | Weighted: %s | Last applied: %s"),
|
||||
Weighting.MatchingDecisionCount,
|
||||
*BuildGuidanceOutcomeActionLabel(Weighting.BaseAction),
|
||||
*BuildGuidanceOutcomeActionLabel(Weighting.WeightedAction),
|
||||
*BuildGuidanceOutcomeActionLabel(Weighting.LastAppliedAction))
|
||||
: TEXT("Weighting: no matching authored decision history yet; the current outcome action is recap-derived only.");
|
||||
Surface.DetailLine = Weighting.IsStructurallyValid()
|
||||
? FString::Printf(
|
||||
TEXT("Decision weighting for this lane/scope: repeat case %d | repeat deck %d | broaden %d | redirect %d | Avg success %.2f | Avg launch cases %.2f | broadened launches %d (avg %.2f) | tightened launches %d (avg %.2f) | Closure continue bias %d | Closure suppress bias %d | Deferred overflow bias %d | Deferred overflow cases %d | %s"),
|
||||
Weighting.RepeatSelectedCaseCount,
|
||||
Weighting.RepeatPreviewDeckCount,
|
||||
Weighting.BroadenPreviewDeckCount,
|
||||
Weighting.RedirectCoachGuidanceCount,
|
||||
Weighting.AverageSuccessRate,
|
||||
Weighting.AverageLaunchCaseCount,
|
||||
Weighting.BroadenedLaunchCount,
|
||||
Weighting.BroadenedLaunchAverageSuccessRate,
|
||||
Weighting.TightenedLaunchCount,
|
||||
Weighting.TightenedLaunchAverageSuccessRate,
|
||||
Weighting.ClosureContinuationBias,
|
||||
Weighting.ClosureSuppressionBias,
|
||||
Weighting.DeferredOverflowContinuationBias,
|
||||
Weighting.DeferredOverflowCaseCount,
|
||||
Weighting.bHasOverride
|
||||
? (Weighting.bUsedDeferredOverflowSignal
|
||||
? TEXT("Deferred-overflow continuation history and authored choices adjusted the current guidance-outcome action.")
|
||||
: (Weighting.bUsedClosureHistorySignal
|
||||
? TEXT("Recent closure-recovery history and authored choices adjusted the current guidance-outcome action.")
|
||||
: TEXT("Recent authored choices adjusted the current guidance-outcome action.")))
|
||||
: TEXT("Recent authored choices reinforced the recap-derived guidance-outcome action."))
|
||||
: TEXT("Weighting detail: apply outcome actions on the same guidance lane and scope to let the dashboard bias future recommendations.");
|
||||
if (Weighting.ReliableAlignedTrustedTightPlanOutcomeHistoryCount > 0
|
||||
|| Weighting.ReliableAlignedTrustedBroadPlanOutcomeHistoryCount > 0
|
||||
|| Weighting.ReliableAlignedTrustedTightContinuationDecisionCount > 0
|
||||
|| Weighting.ReliableAlignedTrustedBroadRedirectDecisionCount > 0)
|
||||
{
|
||||
Surface.DetailLine += FString::Printf(
|
||||
TEXT(" | Aligned launched-plan trust: tight history %d (avg %.2f, continuation decisions %d) | broad history %d (avg %.2f, redirect decisions %d)%s"),
|
||||
Weighting.ReliableAlignedTrustedTightPlanOutcomeHistoryCount,
|
||||
Weighting.ReliableAlignedTrustedTightPlanOutcomeAverageScore,
|
||||
Weighting.ReliableAlignedTrustedTightContinuationDecisionCount,
|
||||
Weighting.ReliableAlignedTrustedBroadPlanOutcomeHistoryCount,
|
||||
Weighting.ReliableAlignedTrustedBroadPlanOutcomeAverageScore,
|
||||
Weighting.ReliableAlignedTrustedBroadRedirectDecisionCount,
|
||||
Weighting.bUsedReliableAlignedPlanOutcomeSignal
|
||||
? TEXT(" | Aligned launched-plan trust adjusted the current guidance-outcome action.")
|
||||
: TEXT(""));
|
||||
}
|
||||
if (Surface.bClosedLoopIdleActionability)
|
||||
{
|
||||
Surface.ResolvedActionLabel = TEXT("Loop Idle");
|
||||
Surface.StatusLine =
|
||||
TEXT("Weighting: retained outcome history remains inspectable, but no live guidance-outcome action is active.");
|
||||
Surface.DetailLine =
|
||||
TEXT("Weighting detail: closed-loop idle preserves authored outcome history for review, but it is not surfacing another repeat, broaden, or redirect action.");
|
||||
}
|
||||
return Surface;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::SelectPreviousMethodDrillFollowUpHistoryEntry()
|
||||
{
|
||||
if (MethodDrillFollowUpHistoryEntries.Num() <= 0)
|
||||
|
|
|
|||
|
|
@ -763,6 +763,18 @@ public:
|
|||
FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface
|
||||
GetSelectedTemplateLaunchHistoryInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardGuidanceComparisonInspectSurface
|
||||
GetDisplayedGuidanceComparisonInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardGuidanceOutcomeInspectSurface
|
||||
GetDisplayedGuidanceOutcomeInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardGuidanceDecisionWeightingInspectSurface
|
||||
GetDisplayedGuidanceDecisionWeightingInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool SelectPreviousMethodDrillFollowUpHistoryEntry();
|
||||
|
||||
|
|
|
|||
|
|
@ -9729,6 +9729,368 @@ struct FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface
|
|||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardGuidanceComparisonInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunRecapSourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TrainingSessionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString GuidanceLaneLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ScopeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString FocusLaneLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BriefHeadline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PrimaryActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewDeckLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActualDeckLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExpectedModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActualModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ExpectedSelectionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActualSelectionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SelectedCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ExpectedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FocusCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CompletedAttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FailureCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TimeoutCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DNFCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalMistakes = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SuccessRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedGuidanceBrief = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedGuidanceDeck = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasComparisonContext = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSingleCaseScope = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSelectedCaseMatchesLastCase = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bClosedLoopIdleActionability = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !DetailLine.IsEmpty()
|
||||
|| bHasDisplayedRunRecap
|
||||
|| bHasComparisonContext;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardGuidanceOutcomeInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunRecapSourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TrainingSessionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString GuidanceLaneLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ScopeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BriefHeadline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BaseActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString WeightedActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SelectedCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ExpectedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CompletedAttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 NonSuccessCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalMistakes = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SuccessRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedGuidanceBrief = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedGuidanceDeck = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasComparisonContext = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSingleCaseScope = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCanApplyAction = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCanRedirectAction = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasWeightingOverride = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsedClosureHistorySignal = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsedDeferredOverflowSignal = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bClosedLoopIdleActionability = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !DetailLine.IsEmpty()
|
||||
|| !ActionLabel.IsEmpty()
|
||||
|| bHasDisplayedRunRecap
|
||||
|| bHasComparisonContext;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardGuidanceDecisionWeightingInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunRecapSourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TrainingSessionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString GuidanceLaneLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ScopeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BriefHeadline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SelectedCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ResolvedActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BaseActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString WeightedActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastAppliedActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 MatchingDecisionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatSelectedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatPreviewDeckCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BroadenPreviewDeckCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RedirectCoachGuidanceCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BroadenedLaunchCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TightenedLaunchCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ClosureContinuationBias = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ClosureSuppressionBias = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DeferredOverflowContinuationBias = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DeferredOverflowCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ReliableAlignedTrustedTightPlanOutcomeHistoryCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ReliableAlignedTrustedBroadPlanOutcomeHistoryCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ReliableAlignedTrustedTightContinuationDecisionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ReliableAlignedTrustedBroadRedirectDecisionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float AverageSuccessRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float AverageLaunchCaseCount = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float BroadenedLaunchAverageSuccessRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float TightenedLaunchAverageSuccessRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float ReliableAlignedTrustedTightPlanOutcomeAverageScore = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float ReliableAlignedTrustedBroadPlanOutcomeAverageScore = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedGuidanceBrief = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedGuidanceDeck = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasComparisonContext = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bSingleCaseScope = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasWeighting = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasWeightingOverride = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsedClosureHistorySignal = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsedDeferredOverflowSignal = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bUsedReliableAlignedPlanOutcomeSignal = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bClosedLoopIdleActionability = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !DetailLine.IsEmpty()
|
||||
|| bHasDisplayedRunRecap
|
||||
|| bHasComparisonContext
|
||||
|| bHasWeighting;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ Current correction call from the source-exposed audit and current execution refr
|
|||
- the latest landed bounded `Phase 4` packet closes the retained-idle comparison/outcome actionability gap at the end of the recognition-assisted coach-to-review continuity lane, and the final retained-surface confirmation pass now leaves that closure lane functionally complete
|
||||
- the retained idle widget surface now keeps retained comparison and decision history inspectable without continuing to advertise live launch or guidance-outcome actions once the coach-to-review loop has already collapsed to truthful closed-loop idle
|
||||
- the now-complete deliberate `UHyperTwistTrainingRuntimeLibrary` world-context consumer lane reaches through active generated-mode selector option owned-execution split-phase current-selection merged ordered roster phase-id lookup, normalized-order lookup, and evaluation-order lookup inspect surfaces, so gameplay/Blueprint callers can inspect one retained merged-roster row directly by phase id, normalized order, or evaluation order without scanning the merged roster array or re-running inspect derivation details directly
|
||||
- the latest landed bounded `Phase 4` packet stays on that same deliberate `UHyperTwistCoachDashboardWidget` retained-history inspect lane and adds selected guidance decision history and selected template launch history inspect surfaces over already-retained dashboard state, so gameplay/Blueprint callers can inspect authored decision retention, launch analytics fragments, and selection provenance without scraping dashboard text blocks or reopening decision-weighting or template-analytics derivation
|
||||
- the dashboard retained-history inspect lane now appears functionally complete through queue-recovery outcome, queue-suppression history, closure-recovery history, method-drill recovery outcome history, method-drill recovery memory history, method-drill follow-up history, handoff history, guidance decision history, and template launch history inspect surfaces; the next clean move is to pivot deliberately to the live dashboard comparison / guidance-outcome / decision-weighting inspect surface trio rather than widening the retained-history seam by drift
|
||||
- the latest landed bounded `Phase 4` packet pivots deliberately off that now-closed `UHyperTwistCoachDashboardWidget` retained-history inspect lane and adds displayed guidance comparison, displayed guidance outcome, and displayed guidance decision-weighting inspect surfaces over the live dashboard recap/comparison state and cached coach actionability state, so gameplay/Blueprint callers can inspect the active comparison target, current outcome action posture, and current authored weighting posture without scraping dashboard text blocks or reopening comparison/outcome derivation
|
||||
- the next clean move is to stay on that same live dashboard guidance-consumer lane and land the active guidance preview selection, preview-case detail, rationale, and guidance-preference inspect surface group rather than drifting back into backend continuity or reopening the already-complete retained-history seam
|
||||
- the current execution-discipline rule that broad refactor / monolith-splitting work should not interrupt the active bounded roadmap packet unless structure is actually blocking it
|
||||
|
||||
## Current execution-reality references
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
# HyperTwist Phase 4 dashboard live guidance comparison, outcome, and decision-weighting inspect surface packet
|
||||
|
||||
- bounded Phase `4` dashboard-consumer slice
|
||||
- date: `2026-05-09`
|
||||
|
||||
## Intent
|
||||
|
||||
Pivot deliberately off the now-complete retained-history inspect lane and expose the live dashboard guidance comparison, guidance-outcome, and decision-weighting state directly to gameplay and Blueprint callers.
|
||||
|
||||
## Why this packet exists
|
||||
|
||||
The dashboard already derived:
|
||||
|
||||
- the active recap-vs-preview comparison target
|
||||
- the current repeat / broaden / redirect guidance-outcome posture
|
||||
- the current authored decision-weighting bias over that same lane and scope
|
||||
|
||||
But that live state still only surfaced through dashboard text blocks and the live action button state. Callers still had to scrape widget presentation or reopen comparison/outcome weighting derivation to inspect what the dashboard was currently showing.
|
||||
|
||||
## What changed
|
||||
|
||||
- added `FHyperTwistTrainingCoachDashboardGuidanceComparisonInspectSurface`
|
||||
- added `FHyperTwistTrainingCoachDashboardGuidanceOutcomeInspectSurface`
|
||||
- added `FHyperTwistTrainingCoachDashboardGuidanceDecisionWeightingInspectSurface`
|
||||
- added `GetDisplayedGuidanceComparisonInspectSurface()`
|
||||
- added `GetDisplayedGuidanceOutcomeInspectSurface()`
|
||||
- added `GetDisplayedGuidanceDecisionWeightingInspectSurface()`
|
||||
- kept the packet bounded to `UHyperTwistCoachDashboardWidget` plus shared surface types, with no dashboard redesign and no backend continuity changes
|
||||
|
||||
## Files
|
||||
|
||||
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Public\HyperTwistTraining\HyperTwistTrainingTypes.h`
|
||||
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Public\HyperTwistTraining\HyperTwistCoachDashboardWidget.h`
|
||||
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Private\HyperTwistTraining\HyperTwistCoachDashboardWidget.cpp`
|
||||
- `C:\HyperTwist\docs\HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md`
|
||||
|
||||
## Outcome
|
||||
|
||||
Gameplay and Blueprint callers can now inspect:
|
||||
|
||||
- the currently displayed recap-vs-preview comparison target with lane, scope, preview-vs-actual deck/mode/selection posture, selected-case alignment, and closed-loop idle comparison posture
|
||||
- the currently displayed guidance-outcome verdict with the live action button label, applyability posture, and closure-history / deferred-overflow adjustments
|
||||
- the currently displayed decision-weighting summary with authored lane/scope bias, aligned launched-plan trust posture, and closed-loop idle weighting posture
|
||||
|
||||
without scraping dashboard text blocks or reopening comparison/outcome/weighting derivation.
|
||||
|
||||
## Validation
|
||||
|
||||
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
|
||||
- passed with `0 Warning(s), 0 Error(s)`
|
||||
|
||||
## Next clean slice
|
||||
|
||||
Stay on the same live dashboard guidance-consumer lane and land the active guidance preview selection, preview-case detail, rationale, and guidance-preference inspect surface group.
|
||||
Loading…
Add table
Reference in a new issue