Expose dashboard run recap status and detail surfaces
This commit is contained in:
parent
7e28d89f50
commit
00c8daf216
5 changed files with 643 additions and 107 deletions
|
|
@ -12318,6 +12318,307 @@ UHyperTwistCoachDashboardWidget::GetDisplayedActiveRunStatusInspectSurface() con
|
|||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardRunRecapStatusInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedRunRecapStatusInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardRunRecapStatusInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Run recap status");
|
||||
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
&& CachedRunState.ActiveDeck.IsStructurallyValid();
|
||||
const bool bHasCurrentRunRecap = bHasActiveRun
|
||||
&& (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();
|
||||
const FString RunRecapSourceLabel = bHasDisplayedRunRecap
|
||||
? (bHasCurrentRunRecap ? TEXT("current run") : TEXT("last completed run"))
|
||||
: (bHasActiveRun ? TEXT("active run") : TEXT("none yet"));
|
||||
const bool bHasActiveTemplateLaunchForDisplayedRun =
|
||||
bHasCurrentRunRecap
|
||||
&& DisplayedRunRecap != nullptr
|
||||
&& !ActiveTemplateLaunchSessionId.IsEmpty()
|
||||
&& DisplayedRunRecap->TrainingSessionId == ActiveTemplateLaunchSessionId
|
||||
&& ActiveTemplateLaunchProvenance.IsStructurallyValid();
|
||||
const bool bHasDisplayedRetainedTemplateLaunch =
|
||||
!bHasCurrentRunRecap
|
||||
&& bHasRetainedTemplateLaunch
|
||||
&& DisplayedRunRecap != nullptr
|
||||
&& !RetainedTemplateLaunchSessionId.IsEmpty()
|
||||
&& DisplayedRunRecap->TrainingSessionId == RetainedTemplateLaunchSessionId
|
||||
&& RetainedTemplateLaunchProvenance.IsStructurallyValid();
|
||||
const FHyperTwistTrainingTemplateLaunchProvenance* DisplayedTemplateLaunch =
|
||||
bHasActiveTemplateLaunchForDisplayedRun
|
||||
? &ActiveTemplateLaunchProvenance
|
||||
: (bHasDisplayedRetainedTemplateLaunch ? &RetainedTemplateLaunchProvenance : nullptr);
|
||||
const FString DisplayedDeckLabel =
|
||||
DisplayedRunRecapDeck != nullptr
|
||||
? (DisplayedRunRecapDeck->Title.IsEmpty()
|
||||
? (DisplayedRunRecapDeck->DeckId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: DisplayedRunRecapDeck->DeckId)
|
||||
: DisplayedRunRecapDeck->Title)
|
||||
: (bHasDisplayedRunRecap && !DisplayedRunRecap->DeckId.IsEmpty()
|
||||
? DisplayedRunRecap->DeckId
|
||||
: TEXT("n/a"));
|
||||
|
||||
Surface.SourceLabel = RunRecapSourceLabel;
|
||||
Surface.TrainingSessionId = bHasDisplayedRunRecap
|
||||
? DisplayedRunRecap->TrainingSessionId
|
||||
: TEXT("n/a");
|
||||
Surface.DeckId = bHasDisplayedRunRecap && !DisplayedRunRecap->DeckId.IsEmpty()
|
||||
? DisplayedRunRecap->DeckId
|
||||
: TEXT("n/a");
|
||||
Surface.DeckLabel = DisplayedDeckLabel;
|
||||
Surface.SessionStateLabel = bHasDisplayedRunRecap
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecap->SessionState)
|
||||
: TEXT("n/a");
|
||||
Surface.DeliveryModeLabel = bHasDisplayedRunRecap
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecapMode)
|
||||
: TEXT("n/a");
|
||||
Surface.CompletedAtUtc = bHasDisplayedRunRecap && !DisplayedRunRecap->LastCompletedAtUtc.IsEmpty()
|
||||
? DisplayedRunRecap->LastCompletedAtUtc
|
||||
: TEXT("n/a");
|
||||
Surface.TemplateId = DisplayedTemplateLaunch != nullptr && !DisplayedTemplateLaunch->TemplateId.IsEmpty()
|
||||
? DisplayedTemplateLaunch->TemplateId
|
||||
: TEXT("n/a");
|
||||
Surface.TemplateKindLabel = DisplayedTemplateLaunch != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedTemplateLaunch->TemplateKind)
|
||||
: TEXT("n/a");
|
||||
Surface.TemplateSourcePlanId =
|
||||
DisplayedTemplateLaunch != nullptr && !DisplayedTemplateLaunch->SourceReviewPlanId.IsEmpty()
|
||||
? DisplayedTemplateLaunch->SourceReviewPlanId
|
||||
: TEXT("none");
|
||||
Surface.bHasDisplayedRunRecap = bHasDisplayedRunRecap;
|
||||
Surface.bHasCurrentRunRecap = bHasCurrentRunRecap;
|
||||
Surface.bHasRetainedRunRecap = !bHasCurrentRunRecap && bHasRetainedRunRecap;
|
||||
Surface.bHasTemplateLaunch = DisplayedTemplateLaunch != nullptr;
|
||||
Surface.bTemplateUsesReviewLane =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
&& (DisplayedTemplateLaunch->bPreferReviewRun
|
||||
|| DisplayedTemplateLaunch->TemplateKind == EHyperTwistTrainingSessionTemplateKind::ReviewPlan
|
||||
|| DisplayedTemplateLaunch->TemplateKind == EHyperTwistTrainingSessionTemplateKind::Coach);
|
||||
Surface.bHasActiveRun = bHasActiveRun;
|
||||
|
||||
Surface.StatusLine = !DisplayedRunRecapStatusLine.IsEmpty()
|
||||
? DisplayedRunRecapStatusLine
|
||||
: (bHasDisplayedRunRecap
|
||||
? (DisplayedTemplateLaunch != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Source: %s | Session: %s | Deck: %s | State: %s | Completed at: %s | Template: %s (%s) | Source plan: %s"),
|
||||
*Surface.SourceLabel,
|
||||
*Surface.TrainingSessionId,
|
||||
*Surface.DeckId,
|
||||
*Surface.SessionStateLabel,
|
||||
*Surface.CompletedAtUtc,
|
||||
*Surface.TemplateId,
|
||||
*Surface.TemplateKindLabel,
|
||||
*Surface.TemplateSourcePlanId)
|
||||
: FString::Printf(
|
||||
TEXT("Source: %s | Session: %s | Deck: %s | State: %s | Completed at: %s"),
|
||||
*Surface.SourceLabel,
|
||||
*Surface.TrainingSessionId,
|
||||
*Surface.DeckId,
|
||||
*Surface.SessionStateLabel,
|
||||
*Surface.CompletedAtUtc))
|
||||
: (bHasActiveRun
|
||||
? TEXT("Source: active run | recap will stabilize here when the run completes or aborts.")
|
||||
: TEXT("Source: none yet | complete a run to retain a session recap on this dashboard.")));
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedRunRecapDetailInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Run recap detail");
|
||||
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
&& CachedRunState.ActiveDeck.IsStructurallyValid();
|
||||
const bool bHasCurrentRunRecap = bHasActiveRun
|
||||
&& (CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|
||||
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
|
||||
const FHyperTwistTrainingSessionSummary* DisplayedRunRecap = bHasCurrentRunRecap
|
||||
? &CachedRunSummary
|
||||
: (bHasRetainedRunRecap ? &RetainedRunRecapSummary : nullptr);
|
||||
const bool bHasDisplayedRunRecap = DisplayedRunRecap != nullptr
|
||||
&& !DisplayedRunRecap->TrainingSessionId.IsEmpty();
|
||||
const FString RunRecapSourceLabel = bHasDisplayedRunRecap
|
||||
? (bHasCurrentRunRecap ? TEXT("current run") : TEXT("last completed run"))
|
||||
: (bHasActiveRun ? TEXT("active run") : TEXT("none yet"));
|
||||
const bool bHasActiveTemplateLaunchForDisplayedRun =
|
||||
bHasCurrentRunRecap
|
||||
&& DisplayedRunRecap != nullptr
|
||||
&& !ActiveTemplateLaunchSessionId.IsEmpty()
|
||||
&& DisplayedRunRecap->TrainingSessionId == ActiveTemplateLaunchSessionId
|
||||
&& ActiveTemplateLaunchProvenance.IsStructurallyValid();
|
||||
const bool bHasDisplayedRetainedTemplateLaunch =
|
||||
!bHasCurrentRunRecap
|
||||
&& bHasRetainedTemplateLaunch
|
||||
&& DisplayedRunRecap != nullptr
|
||||
&& !RetainedTemplateLaunchSessionId.IsEmpty()
|
||||
&& DisplayedRunRecap->TrainingSessionId == RetainedTemplateLaunchSessionId
|
||||
&& RetainedTemplateLaunchProvenance.IsStructurallyValid();
|
||||
const FHyperTwistTrainingTemplateLaunchProvenance* DisplayedTemplateLaunch =
|
||||
bHasActiveTemplateLaunchForDisplayedRun
|
||||
? &ActiveTemplateLaunchProvenance
|
||||
: (bHasDisplayedRetainedTemplateLaunch ? &RetainedTemplateLaunchProvenance : nullptr);
|
||||
const FString DisplayedTemplateLaunchUserId = DisplayedTemplateLaunch != nullptr
|
||||
? (DisplayedTemplateLaunch->UserId.IsEmpty()
|
||||
? (bHasCurrentRunRecap ? CachedRunState.Session.UserId : RetainedRunRecapUserId)
|
||||
: DisplayedTemplateLaunch->UserId)
|
||||
: FString();
|
||||
const FHyperTwistTrainingTemplateLaunchScopedStats* DisplayedTemplateLaunchStats =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
? FindCachedTemplateLaunchScopedStats(
|
||||
DisplayedTemplateLaunch->TemplateId,
|
||||
DisplayedTemplateLaunchUserId)
|
||||
: nullptr;
|
||||
const FString DisplayedTemplateLaunchSelectionDetail =
|
||||
HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchSelectionDetailFragment(
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
&& DisplayedTemplateLaunch->SelectionProvenance.IsStructurallyValid()
|
||||
? &DisplayedTemplateLaunch->SelectionProvenance
|
||||
: nullptr
|
||||
);
|
||||
const bool bDisplayedTemplateLaunchUsesReviewLane =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
&& (DisplayedTemplateLaunch->bPreferReviewRun
|
||||
|| DisplayedTemplateLaunch->TemplateKind == EHyperTwistTrainingSessionTemplateKind::ReviewPlan
|
||||
|| DisplayedTemplateLaunch->TemplateKind == EHyperTwistTrainingSessionTemplateKind::Coach);
|
||||
const FString TemplateAggregateFragment = DisplayedTemplateLaunch != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsOutcomeFragment(
|
||||
DisplayedTemplateLaunchStats)
|
||||
: TEXT("n/a");
|
||||
const FString TemplateAnalyticsDetailFragment = DisplayedTemplateLaunch != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsDetailFragment(
|
||||
DisplayedTemplateLaunchStats)
|
||||
: TEXT("n/a");
|
||||
const FString TemplateTitle = DisplayedTemplateLaunch != nullptr
|
||||
? (DisplayedTemplateLaunch->Title.IsEmpty()
|
||||
? (DisplayedTemplateLaunch->TemplateId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: DisplayedTemplateLaunch->TemplateId)
|
||||
: DisplayedTemplateLaunch->Title)
|
||||
: TEXT("n/a");
|
||||
|
||||
Surface.SourceLabel = RunRecapSourceLabel;
|
||||
Surface.LastCaseId = bHasDisplayedRunRecap && !DisplayedRunRecap->LastCaseId.IsEmpty()
|
||||
? DisplayedRunRecap->LastCaseId
|
||||
: TEXT("n/a");
|
||||
Surface.TemplateTitle = TemplateTitle;
|
||||
Surface.TemplateModeLabel = DisplayedTemplateLaunch != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedTemplateLaunch->SuggestedMode)
|
||||
: TEXT("n/a");
|
||||
Surface.TemplateSelectionLabel = DisplayedTemplateLaunch != nullptr
|
||||
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->SuggestedSelectionPolicy)
|
||||
: TEXT("n/a");
|
||||
Surface.TemplateAggregateFragment = TemplateAggregateFragment;
|
||||
Surface.TemplateAnalyticsDetailFragment = TemplateAnalyticsDetailFragment;
|
||||
Surface.TemplateSelectionDetailFragment = DisplayedTemplateLaunchSelectionDetail;
|
||||
Surface.AttemptCount = bHasDisplayedRunRecap ? DisplayedRunRecap->AttemptCount : 0;
|
||||
Surface.CompletedAttemptCount = bHasDisplayedRunRecap ? DisplayedRunRecap->CompletedAttemptCount : 0;
|
||||
Surface.SuccessCount = bHasDisplayedRunRecap ? DisplayedRunRecap->SuccessCount : 0;
|
||||
Surface.FailureCount = bHasDisplayedRunRecap ? DisplayedRunRecap->FailureCount : 0;
|
||||
Surface.TimeoutCount = bHasDisplayedRunRecap ? DisplayedRunRecap->TimeoutCount : 0;
|
||||
Surface.DNFCount = bHasDisplayedRunRecap ? DisplayedRunRecap->DNFCount : 0;
|
||||
Surface.AbortedCount = bHasDisplayedRunRecap ? DisplayedRunRecap->AbortedCount : 0;
|
||||
Surface.BestTotalTimeMs = bHasDisplayedRunRecap ? DisplayedRunRecap->BestTotalTimeMs : 0;
|
||||
Surface.AverageTotalTimeMs = bHasDisplayedRunRecap ? DisplayedRunRecap->AverageTotalTimeMs : 0;
|
||||
Surface.AverageRawSolveTimeMs = bHasDisplayedRunRecap ? DisplayedRunRecap->AverageRawSolveTimeMs : 0;
|
||||
Surface.AverageInspectionTimeMs = bHasDisplayedRunRecap
|
||||
? DisplayedRunRecap->AverageInspectionTimeMs
|
||||
: 0;
|
||||
Surface.TotalMistakes = bHasDisplayedRunRecap ? DisplayedRunRecap->TotalMistakes : 0;
|
||||
Surface.RecommendedCaseCount = DisplayedTemplateLaunch != nullptr
|
||||
? DisplayedTemplateLaunch->RecommendedCaseCount
|
||||
: 0;
|
||||
Surface.FocusCaseCount = DisplayedTemplateLaunch != nullptr
|
||||
? DisplayedTemplateLaunch->FocusCaseIds.Num()
|
||||
: 0;
|
||||
Surface.SuccessRate = bHasDisplayedRunRecap ? DisplayedRunRecap->SuccessRate : 0.0f;
|
||||
Surface.bHasDisplayedRunRecap = bHasDisplayedRunRecap;
|
||||
Surface.bHasCurrentRunRecap = bHasCurrentRunRecap;
|
||||
Surface.bHasTemplateLaunch = DisplayedTemplateLaunch != nullptr;
|
||||
Surface.bTemplateUsesReviewLane = bDisplayedTemplateLaunchUsesReviewLane;
|
||||
Surface.bHasTemplateSelectionDetail = !DisplayedTemplateLaunchSelectionDetail.IsEmpty();
|
||||
Surface.bHasTemplateAnalytics = DisplayedTemplateLaunchStats != nullptr
|
||||
&& DisplayedTemplateLaunchStats->IsStructurallyValid();
|
||||
|
||||
if (!DisplayedRunRecapDetailLine.IsEmpty())
|
||||
{
|
||||
Surface.DetailLine = DisplayedRunRecapDetailLine;
|
||||
return Surface;
|
||||
}
|
||||
|
||||
if (bHasDisplayedRunRecap)
|
||||
{
|
||||
Surface.DetailLine =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Attempts %d/%d | Success %d | Failure %d | Timeout %d | DNF %d | Aborted %d | Success rate %.2f | Best %d ms | Avg %d ms | Avg raw %d ms | Avg inspection %d ms | Mistakes %d | Last case %s | Template title %s | Template mode %s | Template selection %s | Recommended %d | Focus %d | Review-backed %s | Template aggregate %s | Template detail %s"),
|
||||
Surface.CompletedAttemptCount,
|
||||
Surface.AttemptCount,
|
||||
Surface.SuccessCount,
|
||||
Surface.FailureCount,
|
||||
Surface.TimeoutCount,
|
||||
Surface.DNFCount,
|
||||
Surface.AbortedCount,
|
||||
Surface.SuccessRate,
|
||||
Surface.BestTotalTimeMs,
|
||||
Surface.AverageTotalTimeMs,
|
||||
Surface.AverageRawSolveTimeMs,
|
||||
Surface.AverageInspectionTimeMs,
|
||||
Surface.TotalMistakes,
|
||||
*Surface.LastCaseId,
|
||||
*Surface.TemplateTitle,
|
||||
*Surface.TemplateModeLabel,
|
||||
*Surface.TemplateSelectionLabel,
|
||||
Surface.RecommendedCaseCount,
|
||||
Surface.FocusCaseCount,
|
||||
Surface.bTemplateUsesReviewLane ? TEXT("yes") : TEXT("no"),
|
||||
*Surface.TemplateAggregateFragment,
|
||||
*Surface.TemplateAnalyticsDetailFragment)
|
||||
: FString::Printf(
|
||||
TEXT("Attempts %d/%d | Success %d | Failure %d | Timeout %d | DNF %d | Aborted %d | Success rate %.2f | Best %d ms | Avg %d ms | Avg raw %d ms | Avg inspection %d ms | Mistakes %d | Last case %s"),
|
||||
Surface.CompletedAttemptCount,
|
||||
Surface.AttemptCount,
|
||||
Surface.SuccessCount,
|
||||
Surface.FailureCount,
|
||||
Surface.TimeoutCount,
|
||||
Surface.DNFCount,
|
||||
Surface.AbortedCount,
|
||||
Surface.SuccessRate,
|
||||
Surface.BestTotalTimeMs,
|
||||
Surface.AverageTotalTimeMs,
|
||||
Surface.AverageRawSolveTimeMs,
|
||||
Surface.AverageInspectionTimeMs,
|
||||
Surface.TotalMistakes,
|
||||
*Surface.LastCaseId);
|
||||
if (Surface.bHasTemplateSelectionDetail)
|
||||
{
|
||||
Surface.DetailLine += TEXT(" | ");
|
||||
Surface.DetailLine += Surface.TemplateSelectionDetailFragment;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.DetailLine =
|
||||
TEXT("Recap detail: unavailable until a run has been completed or explicitly aborted.");
|
||||
}
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedActiveAttemptTimerStatusInspectSurface() const
|
||||
{
|
||||
|
|
@ -25242,118 +25543,115 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
RunRecapHeaderTextBlock->SetText(FText::FromString(TEXT("[Run Recap]")));
|
||||
}
|
||||
if (bHasDisplayedRunRecap)
|
||||
{
|
||||
DisplayedRunRecapStatusLine =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Source: %s | Session: %s | Deck: %s | State: %s | Completed at: %s | Template: %s (%s) | Source plan: %s"),
|
||||
*RunRecapSourceLabel,
|
||||
*DisplayedRunRecap->TrainingSessionId,
|
||||
DisplayedRunRecap->DeckId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->DeckId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecap->SessionState),
|
||||
DisplayedRunRecap->LastCompletedAtUtc.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedRunRecap->LastCompletedAtUtc,
|
||||
DisplayedTemplateLaunch->TemplateId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedTemplateLaunch->TemplateId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->TemplateKind),
|
||||
DisplayedTemplateLaunch->SourceReviewPlanId.IsEmpty()
|
||||
? TEXT("none")
|
||||
: *DisplayedTemplateLaunch->SourceReviewPlanId)
|
||||
: FString::Printf(
|
||||
TEXT("Source: %s | Session: %s | Deck: %s | State: %s | Completed at: %s"),
|
||||
*RunRecapSourceLabel,
|
||||
*DisplayedRunRecap->TrainingSessionId,
|
||||
DisplayedRunRecap->DeckId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->DeckId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecap->SessionState),
|
||||
DisplayedRunRecap->LastCompletedAtUtc.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedRunRecap->LastCompletedAtUtc);
|
||||
}
|
||||
else if (bHasActiveRun)
|
||||
{
|
||||
DisplayedRunRecapStatusLine =
|
||||
TEXT("Source: active run | recap will stabilize here when the run completes or aborts.");
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayedRunRecapStatusLine =
|
||||
TEXT("Source: none yet | complete a run to retain a session recap on this dashboard.");
|
||||
}
|
||||
if (RunRecapStatusTextBlock != nullptr)
|
||||
{
|
||||
if (bHasDisplayedRunRecap)
|
||||
RunRecapStatusTextBlock->SetText(FText::FromString(DisplayedRunRecapStatusLine));
|
||||
}
|
||||
if (bHasDisplayedRunRecap)
|
||||
{
|
||||
DisplayedRunRecapDetailLine =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Attempts %d/%d | Success %d | Failure %d | Timeout %d | DNF %d | Aborted %d | Success rate %.2f | Best %d ms | Avg %d ms | Avg raw %d ms | Avg inspection %d ms | Mistakes %d | Last case %s | Template title %s | Template mode %s | Template selection %s | Recommended %d | Focus %d | Review-backed %s | Template aggregate %s | Template detail %s"),
|
||||
DisplayedRunRecap->CompletedAttemptCount,
|
||||
DisplayedRunRecap->AttemptCount,
|
||||
DisplayedRunRecap->SuccessCount,
|
||||
DisplayedRunRecap->FailureCount,
|
||||
DisplayedRunRecap->TimeoutCount,
|
||||
DisplayedRunRecap->DNFCount,
|
||||
DisplayedRunRecap->AbortedCount,
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
DisplayedRunRecap->BestTotalTimeMs,
|
||||
DisplayedRunRecap->AverageTotalTimeMs,
|
||||
DisplayedRunRecap->AverageRawSolveTimeMs,
|
||||
DisplayedRunRecap->AverageInspectionTimeMs,
|
||||
DisplayedRunRecap->TotalMistakes,
|
||||
DisplayedRunRecap->LastCaseId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->LastCaseId,
|
||||
DisplayedTemplateLaunch->Title.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedTemplateLaunch->Title,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->SuggestedMode),
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->SuggestedSelectionPolicy),
|
||||
DisplayedTemplateLaunch->RecommendedCaseCount,
|
||||
DisplayedTemplateLaunch->FocusCaseIds.Num(),
|
||||
bDisplayedTemplateLaunchUsesReviewLane ? TEXT("yes") : TEXT("no"),
|
||||
*HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsOutcomeFragment(
|
||||
DisplayedTemplateLaunchStats),
|
||||
*HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsDetailFragment(
|
||||
DisplayedTemplateLaunchStats))
|
||||
: FString::Printf(
|
||||
TEXT("Attempts %d/%d | Success %d | Failure %d | Timeout %d | DNF %d | Aborted %d | Success rate %.2f | Best %d ms | Avg %d ms | Avg raw %d ms | Avg inspection %d ms | Mistakes %d | Last case %s"),
|
||||
DisplayedRunRecap->CompletedAttemptCount,
|
||||
DisplayedRunRecap->AttemptCount,
|
||||
DisplayedRunRecap->SuccessCount,
|
||||
DisplayedRunRecap->FailureCount,
|
||||
DisplayedRunRecap->TimeoutCount,
|
||||
DisplayedRunRecap->DNFCount,
|
||||
DisplayedRunRecap->AbortedCount,
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
DisplayedRunRecap->BestTotalTimeMs,
|
||||
DisplayedRunRecap->AverageTotalTimeMs,
|
||||
DisplayedRunRecap->AverageRawSolveTimeMs,
|
||||
DisplayedRunRecap->AverageInspectionTimeMs,
|
||||
DisplayedRunRecap->TotalMistakes,
|
||||
DisplayedRunRecap->LastCaseId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->LastCaseId);
|
||||
if (!DisplayedTemplateLaunchSelectionDetail.IsEmpty())
|
||||
{
|
||||
RunRecapStatusTextBlock->SetText(FText::FromString(
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Source: %s | Session: %s | Deck: %s | State: %s | Completed at: %s | Template: %s (%s) | Source plan: %s"),
|
||||
*RunRecapSourceLabel,
|
||||
*DisplayedRunRecap->TrainingSessionId,
|
||||
DisplayedRunRecap->DeckId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->DeckId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecap->SessionState),
|
||||
DisplayedRunRecap->LastCompletedAtUtc.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedRunRecap->LastCompletedAtUtc,
|
||||
DisplayedTemplateLaunch->TemplateId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedTemplateLaunch->TemplateId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->TemplateKind),
|
||||
DisplayedTemplateLaunch->SourceReviewPlanId.IsEmpty()
|
||||
? TEXT("none")
|
||||
: *DisplayedTemplateLaunch->SourceReviewPlanId)
|
||||
: FString::Printf(
|
||||
TEXT("Source: %s | Session: %s | Deck: %s | State: %s | Completed at: %s"),
|
||||
*RunRecapSourceLabel,
|
||||
*DisplayedRunRecap->TrainingSessionId,
|
||||
DisplayedRunRecap->DeckId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->DeckId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(DisplayedRunRecap->SessionState),
|
||||
DisplayedRunRecap->LastCompletedAtUtc.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedRunRecap->LastCompletedAtUtc)
|
||||
));
|
||||
}
|
||||
else if (bHasActiveRun)
|
||||
{
|
||||
RunRecapStatusTextBlock->SetText(FText::FromString(
|
||||
TEXT("Source: active run | recap will stabilize here when the run completes or aborts.")
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
RunRecapStatusTextBlock->SetText(FText::FromString(
|
||||
TEXT("Source: none yet | complete a run to retain a session recap on this dashboard.")
|
||||
));
|
||||
DisplayedRunRecapDetailLine += TEXT(" | ");
|
||||
DisplayedRunRecapDetailLine += DisplayedTemplateLaunchSelectionDetail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayedRunRecapDetailLine =
|
||||
TEXT("Recap detail: unavailable until a run has been completed or explicitly aborted.");
|
||||
}
|
||||
if (RunRecapDetailTextBlock != nullptr)
|
||||
{
|
||||
if (bHasDisplayedRunRecap)
|
||||
{
|
||||
FString RunRecapDetailLine =
|
||||
DisplayedTemplateLaunch != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Attempts %d/%d | Success %d | Failure %d | Timeout %d | DNF %d | Aborted %d | Success rate %.2f | Best %d ms | Avg %d ms | Avg raw %d ms | Avg inspection %d ms | Mistakes %d | Last case %s | Template title %s | Template mode %s | Template selection %s | Recommended %d | Focus %d | Review-backed %s | Template aggregate %s | Template detail %s"),
|
||||
DisplayedRunRecap->CompletedAttemptCount,
|
||||
DisplayedRunRecap->AttemptCount,
|
||||
DisplayedRunRecap->SuccessCount,
|
||||
DisplayedRunRecap->FailureCount,
|
||||
DisplayedRunRecap->TimeoutCount,
|
||||
DisplayedRunRecap->DNFCount,
|
||||
DisplayedRunRecap->AbortedCount,
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
DisplayedRunRecap->BestTotalTimeMs,
|
||||
DisplayedRunRecap->AverageTotalTimeMs,
|
||||
DisplayedRunRecap->AverageRawSolveTimeMs,
|
||||
DisplayedRunRecap->AverageInspectionTimeMs,
|
||||
DisplayedRunRecap->TotalMistakes,
|
||||
DisplayedRunRecap->LastCaseId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->LastCaseId,
|
||||
DisplayedTemplateLaunch->Title.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *DisplayedTemplateLaunch->Title,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->SuggestedMode),
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
|
||||
DisplayedTemplateLaunch->SuggestedSelectionPolicy),
|
||||
DisplayedTemplateLaunch->RecommendedCaseCount,
|
||||
DisplayedTemplateLaunch->FocusCaseIds.Num(),
|
||||
bDisplayedTemplateLaunchUsesReviewLane ? TEXT("yes") : TEXT("no"),
|
||||
*HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsOutcomeFragment(
|
||||
DisplayedTemplateLaunchStats),
|
||||
*HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsDetailFragment(
|
||||
DisplayedTemplateLaunchStats))
|
||||
: FString::Printf(
|
||||
TEXT("Attempts %d/%d | Success %d | Failure %d | Timeout %d | DNF %d | Aborted %d | Success rate %.2f | Best %d ms | Avg %d ms | Avg raw %d ms | Avg inspection %d ms | Mistakes %d | Last case %s"),
|
||||
DisplayedRunRecap->CompletedAttemptCount,
|
||||
DisplayedRunRecap->AttemptCount,
|
||||
DisplayedRunRecap->SuccessCount,
|
||||
DisplayedRunRecap->FailureCount,
|
||||
DisplayedRunRecap->TimeoutCount,
|
||||
DisplayedRunRecap->DNFCount,
|
||||
DisplayedRunRecap->AbortedCount,
|
||||
DisplayedRunRecap->SuccessRate,
|
||||
DisplayedRunRecap->BestTotalTimeMs,
|
||||
DisplayedRunRecap->AverageTotalTimeMs,
|
||||
DisplayedRunRecap->AverageRawSolveTimeMs,
|
||||
DisplayedRunRecap->AverageInspectionTimeMs,
|
||||
DisplayedRunRecap->TotalMistakes,
|
||||
DisplayedRunRecap->LastCaseId.IsEmpty() ? TEXT("n/a") : *DisplayedRunRecap->LastCaseId);
|
||||
if (!DisplayedTemplateLaunchSelectionDetail.IsEmpty())
|
||||
{
|
||||
RunRecapDetailLine += TEXT(" | ");
|
||||
RunRecapDetailLine += DisplayedTemplateLaunchSelectionDetail;
|
||||
}
|
||||
RunRecapDetailTextBlock->SetText(FText::FromString(RunRecapDetailLine));
|
||||
}
|
||||
else
|
||||
{
|
||||
RunRecapDetailTextBlock->SetText(FText::FromString(
|
||||
TEXT("Recap detail: unavailable until a run has been completed or explicitly aborted.")
|
||||
));
|
||||
}
|
||||
RunRecapDetailTextBlock->SetText(FText::FromString(DisplayedRunRecapDetailLine));
|
||||
}
|
||||
if (GuidanceComparisonHeaderTextBlock != nullptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -875,6 +875,14 @@ public:
|
|||
FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface
|
||||
GetDisplayedActiveRunStatusInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardRunRecapStatusInspectSurface
|
||||
GetDisplayedRunRecapStatusInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface
|
||||
GetDisplayedRunRecapDetailInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
|
||||
GetDisplayedActiveAttemptTimerStatusInspectSurface() const;
|
||||
|
|
@ -2014,6 +2022,8 @@ private:
|
|||
FString DisplayedTransitionStatusLine;
|
||||
FString DisplayedActiveRunStatusLine;
|
||||
FString DisplayedActiveRunSummaryLine;
|
||||
FString DisplayedRunRecapStatusLine;
|
||||
FString DisplayedRunRecapDetailLine;
|
||||
FString DisplayedCurrentCasePromptLine;
|
||||
FString DisplayedCurrentCaseNotationLine;
|
||||
FString DisplayedAttemptTimeHintLabel;
|
||||
|
|
|
|||
|
|
@ -13300,6 +13300,179 @@ struct FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface
|
|||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardRunRecapStatusInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TrainingSessionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SessionStateLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeliveryModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CompletedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateKindLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateSourcePlanId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasCurrentRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasRetainedRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasTemplateLaunch = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bTemplateUsesReviewLane = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasActiveRun = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| bHasDisplayedRunRecap
|
||||
|| bHasActiveRun;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateTitle;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateSelectionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateAggregateFragment;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateAnalyticsDetailFragment;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TemplateSelectionDetailFragment;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CompletedAttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SuccessCount = 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 AbortedCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BestTotalTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AverageTotalTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AverageRawSolveTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AverageInspectionTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalMistakes = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RecommendedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FocusCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float SuccessRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDisplayedRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasCurrentRunRecap = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasTemplateLaunch = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bTemplateUsesReviewLane = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasTemplateSelectionDetail = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasTemplateAnalytics = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !DetailLine.IsEmpty()
|
||||
|| bHasDisplayedRunRecap
|
||||
|| bHasTemplateLaunch;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 pivots deliberately into the next unsurfaced live dashboard presentation band and adds displayed method-drill diagnostics and displayed drill follow-up action inspect surfaces over already-cached method-drill diagnostic, follow-up template, follow-up deck, and retained follow-up-weighting state, so gameplay/Blueprint callers can inspect the exact displayed diagnostics lines and surfaced drill follow-up label without scraping widget text or reopening that derivation path
|
||||
- the next best clean move is to stay on that same live dashboard consumer lane and expose the dedicated run-recap status/detail inspect surface over the current-or-retained recap presentation band
|
||||
- the latest landed bounded `Phase 4` packet stays on that same live dashboard consumer lane and adds dedicated run-recap status and run-recap detail inspect surfaces over the current-or-retained recap presentation band, so gameplay/Blueprint callers can inspect the exact displayed recap lines plus the retained session/template context behind them without scraping widget text or reopening recap derivation
|
||||
- the next best clean move is to stay adjacent in that same live dashboard consumer lane and expose the run-recap repeat/dismiss action control surface over the already-retained recap action labels and enablement posture
|
||||
- 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
|
||||
|
||||
## Donor portfolio phase taxonomy
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
# HyperTwist Phase 4 dashboard live run-recap status/detail inspect surface packet
|
||||
|
||||
- bounded Phase `4` dashboard-consumer slice
|
||||
- date: `2026-05-10`
|
||||
|
||||
## Intent
|
||||
|
||||
Stay adjacent in the live dashboard consumer lane and expose the current-or-retained run-recap presentation directly to gameplay and Blueprint callers.
|
||||
|
||||
## Why this packet exists
|
||||
|
||||
`UHyperTwistCoachDashboardWidget` already displayed:
|
||||
|
||||
- the live run-recap status line
|
||||
- the live run-recap detail line
|
||||
- the retained current-run versus last-completed-run recap posture behind that band
|
||||
|
||||
But that recap band still only surfaced through widget text blocks. Callers still had to scrape UI text to understand which recap source is currently being shown, what completed-session payload is being summarized, and whether template-launch provenance is attached to that recap.
|
||||
|
||||
## What changed
|
||||
|
||||
- added `FHyperTwistTrainingCoachDashboardRunRecapStatusInspectSurface`
|
||||
- added `FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface`
|
||||
- added `GetDisplayedRunRecapStatusInspectSurface()`
|
||||
- added `GetDisplayedRunRecapDetailInspectSurface()`
|
||||
- retained the exact displayed run-recap status/detail lines inside the widget so the new surfaces report the same live strings the dashboard is already presenting
|
||||
- kept the packet bounded to `UHyperTwistCoachDashboardWidget` plus shared surface types, with no recap-persistence refactor 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 exact displayed live run-recap status line
|
||||
- the exact displayed live run-recap detail line
|
||||
- whether the recap is coming from the current completed/aborted run or the retained last-completed run
|
||||
- the retained session summary metrics behind that band
|
||||
- the attached template-launch provenance and template analytics fragments when that recap came from a template-backed launch
|
||||
|
||||
without scraping widget text or reopening run-recap 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 consumer lane and expose the run-recap repeat/dismiss action control surface over the already-retained recap action labels and enablement posture.
|
||||
Loading…
Add table
Reference in a new issue