Expose dashboard decision and template history inspect surfaces

This commit is contained in:
axiomlogicnexus 2026-05-09 18:26:58 +02:00
parent 0c16748821
commit 6246f41e5c
5 changed files with 710 additions and 2 deletions

View file

@ -8173,6 +8173,342 @@ UHyperTwistCoachDashboardWidget::GetSelectedHandoffHistoryInspectSurface() const
return Surface;
}
FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface
UHyperTwistCoachDashboardWidget::GetSelectedGuidanceDecisionHistoryInspectSurface() const
{
FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface Surface;
Surface.Headline = TEXT("Decision history");
Surface.SelectedEntryIndex = SelectedGuidanceDecisionIndex;
Surface.HistoryEntryCount = GuidanceDecisionHistoryEntries.Num();
Surface.bClosedLoopIdleActionability = IsCoachLoopActionabilityClosed();
const auto BuildDecisionActionLabel =
[this](const EHyperTwistCoachDashboardOutcomeAction Action) -> FString
{
return Action == EHyperTwistCoachDashboardOutcomeAction::None
? TEXT("none")
: BuildGuidanceOutcomeActionLabel(Action);
};
const EHyperTwistCoachDashboardOutcomeAction BaseAction = DeriveGuidanceOutcomeAction();
const FHyperTwistCoachDashboardDecisionWeighting Weighting =
BuildGuidanceDecisionWeighting(BaseAction);
Surface.bHasWeighting = Weighting.IsStructurallyValid();
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.bHasWeightingOverride = Weighting.bHasOverride;
Surface.bUsedClosureHistorySignal = Weighting.bUsedClosureHistorySignal;
Surface.bUsedDeferredOverflowSignal = Weighting.bUsedDeferredOverflowSignal;
Surface.bUsedReliableAlignedPlanOutcomeSignal =
Weighting.bUsedReliableAlignedPlanOutcomeSignal;
Surface.BaseActionLabel = BuildDecisionActionLabel(Weighting.BaseAction);
Surface.WeightedActionLabel = BuildDecisionActionLabel(Weighting.WeightedAction);
Surface.LastAppliedActionLabel = BuildDecisionActionLabel(Weighting.LastAppliedAction);
Surface.WeightingStatusLine = 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.WeightingDetailLine = 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.WeightingDetailLine += 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.WeightingStatusLine =
TEXT("Weighting: retained outcome history remains inspectable, but no live guidance-outcome action is active.");
Surface.WeightingDetailLine =
TEXT("Weighting detail: closed-loop idle preserves authored outcome history for review, but it is not surfacing another repeat, broaden, or redirect action.");
}
const FHyperTwistCoachDashboardDecisionHistoryEntry* SelectedEntry =
SelectedGuidanceDecisionIndex >= 0
&& SelectedGuidanceDecisionIndex < GuidanceDecisionHistoryEntries.Num()
? &GuidanceDecisionHistoryEntries[SelectedGuidanceDecisionIndex]
: nullptr;
Surface.bHasSelectedEntry =
SelectedEntry != nullptr && SelectedEntry->IsStructurallyValid();
if (!Surface.bHasSelectedEntry)
{
Surface.StatusLine =
TEXT("Decision history: no applied guidance-outcome decisions recorded yet.");
Surface.DetailLine =
TEXT("Decision detail: apply a guidance outcome from the dashboard to retain the authored choice history.");
if (Surface.bClosedLoopIdleActionability)
{
Surface.StatusLine =
TEXT("Decision history: no applied guidance-outcome decisions are selected; retained decision history remains inspectable in the closed-loop idle state.");
Surface.DetailLine =
TEXT("Decision detail: the coach-to-review loop is closed and idle, so no live guidance-outcome action is being surfaced for application.");
}
return Surface;
}
Surface.RecordedAtUtc = SelectedEntry->RecordedAtUtc;
Surface.SourceSessionId = SelectedEntry->SourceSessionId;
Surface.GuidanceLaneLabel =
SelectedEntry->GuidanceLane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
? TEXT("recommended")
: (SelectedEntry->GuidanceLane
== EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
? TEXT("follow-up")
: TEXT("none"));
Surface.ScopeLabel =
SelectedEntry->bSingleCaseScope ? TEXT("selected case") : TEXT("preview deck");
Surface.BriefHeadline =
SelectedEntry->BriefHeadline.IsEmpty() ? TEXT("n/a") : SelectedEntry->BriefHeadline;
Surface.RecommendedActionLabel = SelectedEntry->RecommendedActionLabel;
Surface.AppliedActionLabel = SelectedEntry->AppliedActionLabel;
Surface.SelectedCaseId =
SelectedEntry->SelectedCaseId.IsEmpty() ? TEXT("n/a") : SelectedEntry->SelectedCaseId;
Surface.LaunchBudgetReasonLine =
SelectedEntry->LaunchBudgetReasonLine.IsEmpty()
? TEXT("n/a")
: SelectedEntry->LaunchBudgetReasonLine;
Surface.CompletedAttemptCount = SelectedEntry->CompletedAttemptCount;
Surface.TotalMistakes = SelectedEntry->TotalMistakes;
Surface.LaunchedCaseCount = SelectedEntry->LaunchedCaseCount;
Surface.ReferenceCaseCount = SelectedEntry->ReferenceCaseCount;
Surface.SuccessRate = SelectedEntry->SuccessRate;
Surface.bSingleCaseScope = SelectedEntry->bSingleCaseScope;
Surface.bBroadenedLaunchScope = SelectedEntry->bBroadenedLaunchScope;
Surface.bTightenedLaunchScope = SelectedEntry->bTightenedLaunchScope;
Surface.bUsedReliableAlignedTrustedTightPlanOutcomeHistory =
SelectedEntry->bUsedReliableAlignedTrustedTightPlanOutcomeHistory;
Surface.bUsedReliableAlignedTrustedBroadPlanOutcomeHistory =
SelectedEntry->bUsedReliableAlignedTrustedBroadPlanOutcomeHistory;
Surface.StatusLine = FString::Printf(
TEXT("Decision history: %d entries | selected %d/%d | Lane: %s | Scope: %s | Recorded: %s"),
GuidanceDecisionHistoryEntries.Num(),
SelectedGuidanceDecisionIndex + 1,
GuidanceDecisionHistoryEntries.Num(),
*Surface.GuidanceLaneLabel,
*Surface.ScopeLabel,
*SelectedEntry->RecordedAtUtc);
Surface.DetailLine = FString::Printf(
TEXT("Session: %s | Brief: %s | Recommended: %s | Applied: %s | Selected case: %s | Launch cases: %d/%d | Scope: %s | Success rate: %.2f | Completed attempts: %d | Mistakes: %d | Budget reason: %s"),
*SelectedEntry->SourceSessionId,
*Surface.BriefHeadline,
*SelectedEntry->RecommendedActionLabel,
*SelectedEntry->AppliedActionLabel,
*Surface.SelectedCaseId,
SelectedEntry->LaunchedCaseCount,
SelectedEntry->ReferenceCaseCount,
SelectedEntry->bBroadenedLaunchScope
? TEXT("broadened")
: (SelectedEntry->bTightenedLaunchScope
? TEXT("tightened")
: TEXT("steady")),
SelectedEntry->SuccessRate,
SelectedEntry->CompletedAttemptCount,
SelectedEntry->TotalMistakes,
*Surface.LaunchBudgetReasonLine);
if (SelectedEntry->ReliableAlignedTrustedTightPlanOutcomeHistoryCount > 0
|| SelectedEntry->ReliableAlignedTrustedBroadPlanOutcomeHistoryCount > 0
|| SelectedEntry->bUsedReliableAlignedTrustedTightPlanOutcomeHistory
|| SelectedEntry->bUsedReliableAlignedTrustedBroadPlanOutcomeHistory)
{
Surface.DetailLine += FString::Printf(
TEXT(" | Aligned launched-plan trust: tight history %d (avg %.2f) | broad history %d (avg %.2f)%s"),
SelectedEntry->ReliableAlignedTrustedTightPlanOutcomeHistoryCount,
SelectedEntry->ReliableAlignedTrustedTightPlanOutcomeAverageScore,
SelectedEntry->ReliableAlignedTrustedBroadPlanOutcomeHistoryCount,
SelectedEntry->ReliableAlignedTrustedBroadPlanOutcomeAverageScore,
SelectedEntry->bUsedReliableAlignedTrustedTightPlanOutcomeHistory
? TEXT(" | This decision was taken while tight aligned launched-plan trust was active.")
: (SelectedEntry->bUsedReliableAlignedTrustedBroadPlanOutcomeHistory
? TEXT(" | This decision was taken while broad aligned launched-plan redirect trust was active.")
: TEXT("")));
}
return Surface;
}
FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface
UHyperTwistCoachDashboardWidget::GetSelectedTemplateLaunchHistoryInspectSurface() const
{
FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface Surface;
Surface.Headline = TEXT("Template launch history");
Surface.SelectedEntryIndex = SelectedTemplateLaunchHistoryIndex;
Surface.HistoryEntryCount = TemplateLaunchHistoryEntries.Num();
const FHyperTwistCoachDashboardTemplateLaunchHistoryEntry* SelectedEntry =
SelectedTemplateLaunchHistoryIndex >= 0
&& SelectedTemplateLaunchHistoryIndex < TemplateLaunchHistoryEntries.Num()
? &TemplateLaunchHistoryEntries[SelectedTemplateLaunchHistoryIndex]
: nullptr;
Surface.bHasSelectedEntry =
SelectedEntry != nullptr && SelectedEntry->IsStructurallyValid();
if (!Surface.bHasSelectedEntry)
{
Surface.StatusLine =
TEXT("Template launch history: no completed template-backed runs retained yet.");
Surface.DetailLine =
TEXT("Template launch history detail: completed runs started through the dashboard template lane will accumulate here with template id, template kind, and source review-plan provenance.");
return Surface;
}
const FHyperTwistTrainingTemplateLaunchScopedStats* SelectedStats =
FindCachedTemplateLaunchScopedStats(
SelectedEntry->TemplateId,
SelectedEntry->UserId);
Surface.bHasScopedStats =
SelectedStats != nullptr && SelectedStats->IsStructurallyValid();
Surface.bHasSelectionProvenance =
SelectedEntry->SelectionProvenance.IsStructurallyValid();
Surface.SelectionProvenance = Surface.bHasSelectionProvenance
? SelectedEntry->SelectionProvenance
: FHyperTwistTrainingTemplateLaunchSelectionProvenance();
Surface.AnalyticsOutcomeLine =
HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsOutcomeFragment(
SelectedStats);
Surface.AnalyticsDetailLine =
HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchAnalyticsDetailFragment(
SelectedStats);
Surface.SelectionDetailLine =
HyperTwistCoachDashboardWidgetInternal::BuildTemplateLaunchSelectionDetailFragment(
Surface.bHasSelectionProvenance ? &SelectedEntry->SelectionProvenance : nullptr);
Surface.RecordedAtUtc = SelectedEntry->RecordedAtUtc;
Surface.CompletedAtUtc =
SelectedEntry->CompletedAtUtc.IsEmpty() ? TEXT("n/a") : SelectedEntry->CompletedAtUtc;
Surface.SourceSessionId = SelectedEntry->SourceSessionId;
Surface.TemplateId =
SelectedEntry->TemplateId.IsEmpty() ? TEXT("n/a") : SelectedEntry->TemplateId;
Surface.TemplateTitle =
SelectedEntry->TemplateTitle.IsEmpty() ? TEXT("n/a") : SelectedEntry->TemplateTitle;
Surface.UserId = SelectedEntry->UserId.IsEmpty() ? TEXT("n/a") : SelectedEntry->UserId;
Surface.FocusDeckId =
SelectedEntry->FocusDeckId.IsEmpty() ? TEXT("n/a") : SelectedEntry->FocusDeckId;
Surface.SourceReviewPlanId =
SelectedEntry->SourceReviewPlanId.IsEmpty()
? TEXT("none")
: SelectedEntry->SourceReviewPlanId;
Surface.TemplateKind = SelectedEntry->TemplateKind;
Surface.TemplateKindLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->TemplateKind);
Surface.SessionState = SelectedEntry->SessionState;
Surface.SessionStateLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->SessionState);
Surface.SuggestedMode = SelectedEntry->SuggestedMode;
Surface.SuggestedModeLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->SuggestedMode);
Surface.SuggestedSelectionPolicy = SelectedEntry->SuggestedSelectionPolicy;
Surface.SuggestedSelectionLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->SuggestedSelectionPolicy);
Surface.RecommendedCaseCount = SelectedEntry->RecommendedCaseCount;
Surface.FocusCaseCount = SelectedEntry->FocusCaseCount;
Surface.CompletedAttemptCount = SelectedEntry->CompletedAttemptCount;
Surface.TotalMistakes = SelectedEntry->TotalMistakes;
Surface.SuccessRate = SelectedEntry->SuccessRate;
Surface.bPreferReviewRun = SelectedEntry->bPreferReviewRun;
Surface.bCoachReview = SelectedEntry->bCoachReview;
Surface.bPreferShortReviewSet = SelectedEntry->bPreferShortReviewSet;
Surface.StatusLine = FString::Printf(
TEXT("Template launch history: %d entries | selected %d/%d | Template: %s | State: %s | Completed: %s | Aggregate: %s"),
TemplateLaunchHistoryEntries.Num(),
SelectedTemplateLaunchHistoryIndex + 1,
TemplateLaunchHistoryEntries.Num(),
*Surface.TemplateId,
*Surface.SessionStateLabel,
*Surface.CompletedAtUtc,
*Surface.AnalyticsOutcomeLine);
Surface.DetailLine = FString::Printf(
TEXT("Title: %s | kind: %s | mode: %s | selection: %s | deck: %s | user: %s | source plan: %s | recommended %d | focus %d | attempts %d | success %.2f | mistakes %d | review-backed: %s | coach-review: %s | short set: %s | Aggregate detail: %s"),
*Surface.TemplateTitle,
*Surface.TemplateKindLabel,
*Surface.SuggestedModeLabel,
*Surface.SuggestedSelectionLabel,
*Surface.FocusDeckId,
*Surface.UserId,
*Surface.SourceReviewPlanId,
SelectedEntry->RecommendedCaseCount,
SelectedEntry->FocusCaseCount,
SelectedEntry->CompletedAttemptCount,
SelectedEntry->SuccessRate,
SelectedEntry->TotalMistakes,
SelectedEntry->bPreferReviewRun ? TEXT("yes") : TEXT("no"),
SelectedEntry->bCoachReview ? TEXT("yes") : TEXT("no"),
SelectedEntry->bPreferShortReviewSet ? TEXT("yes") : TEXT("no"),
*Surface.AnalyticsDetailLine);
if (!Surface.SelectionDetailLine.IsEmpty())
{
Surface.DetailLine += TEXT(" | ");
Surface.DetailLine += Surface.SelectionDetailLine;
}
return Surface;
}
bool UHyperTwistCoachDashboardWidget::SelectPreviousMethodDrillFollowUpHistoryEntry()
{
if (MethodDrillFollowUpHistoryEntries.Num() <= 0)

View file

@ -755,6 +755,14 @@ public:
FHyperTwistTrainingCoachDashboardHandoffHistoryInspectSurface
GetSelectedHandoffHistoryInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface
GetSelectedGuidanceDecisionHistoryInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface
GetSelectedTemplateLaunchHistoryInspectSurface() const;
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
bool SelectPreviousMethodDrillFollowUpHistoryEntry();

View file

@ -9415,6 +9415,320 @@ struct FHyperTwistTrainingCoachDashboardHandoffHistoryInspectSurface
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface
{
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 WeightingStatusLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString WeightingDetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecordedAtUtc;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SourceSessionId;
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 RecommendedActionLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString AppliedActionLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedCaseId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LaunchBudgetReasonLine;
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 SelectedEntryIndex = INDEX_NONE;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 HistoryEntryCount = 0;
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")
int32 CompletedAttemptCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 TotalMistakes = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 LaunchedCaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ReferenceCaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float SuccessRate = 0.0f;
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 bHasSelectedEntry = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasWeighting = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSingleCaseScope = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bBroadenedLaunchScope = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bTightenedLaunchScope = 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 bUsedReliableAlignedTrustedTightPlanOutcomeHistory = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bUsedReliableAlignedTrustedBroadPlanOutcomeHistory = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bClosedLoopIdleActionability = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| !WeightingStatusLine.IsEmpty()
|| !WeightingDetailLine.IsEmpty()
|| bHasSelectedEntry
|| bHasWeighting
|| HistoryEntryCount > 0;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface
{
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 AnalyticsOutcomeLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString AnalyticsDetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectionDetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecordedAtUtc;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString CompletedAtUtc;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SourceSessionId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString TemplateId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString TemplateTitle;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString UserId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString FocusDeckId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SourceReviewPlanId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString TemplateKindLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SessionStateLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SuggestedModeLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SuggestedSelectionLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 SelectedEntryIndex = INDEX_NONE;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 HistoryEntryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RecommendedCaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 FocusCaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 CompletedAttemptCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 TotalMistakes = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float SuccessRate = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchSelectionProvenance SelectionProvenance;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
EHyperTwistTrainingSessionTemplateKind TemplateKind =
EHyperTwistTrainingSessionTemplateKind::Recovery;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
EHyperTwistTrainingSessionState SessionState =
EHyperTwistTrainingSessionState::Created;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
EHyperTwistTrainingDeliveryMode SuggestedMode =
EHyperTwistTrainingDeliveryMode::Timer;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
EHyperTwistTrainingSelectionPolicy SuggestedSelectionPolicy =
EHyperTwistTrainingSelectionPolicy::Weighted;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelectedEntry = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasScopedStats = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelectionProvenance = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreferReviewRun = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCoachReview = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreferShortReviewSet = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bHasSelectedEntry
|| HistoryEntryCount > 0;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface
{

View file

@ -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 method-drill follow-up history and selected handoff history inspect surfaces over already-retained dashboard state, so gameplay/Blueprint callers can inspect retained drill follow-up recap posture and retained handoff-pattern shifts without scraping dashboard text blocks or reopening follow-up weighting or handoff-memory derivation
- the current next bounded packet should stay on that same dashboard retained-history inspect lane only while a real gameplay or Blueprint caller still needs one more thin inspect contract over already-retained dashboard history state; the next clean move inside that lane is the guidance decision history and template launch history inspect pair rather than widening back into backend continuity or runtime-library drift
- 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 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

View file

@ -0,0 +1,50 @@
# HyperTwist Phase 4 dashboard guidance decision and template launch history inspect surface packet
- bounded Phase `4` dashboard-consumer slice
- date: `2026-05-09`
## Intent
Stay on the deliberate `UHyperTwistCoachDashboardWidget` retained-history inspect lane and expose the last two retained dashboard history families directly to gameplay and Blueprint callers.
## Why this packet exists
The dashboard already retained:
- selected guidance decision history entries and their current decision-weighting posture
- selected template launch history entries plus retained template-launch analytics and selection provenance
But that state still only surfaced through dashboard text blocks and selection actions. Callers still had to scrape widget presentation or reopen decision-weighting and template-analytics derivation to inspect retained orchestration history directly.
## What changed
- added `FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface`
- added `FHyperTwistTrainingCoachDashboardTemplateLaunchHistoryInspectSurface`
- added `GetSelectedGuidanceDecisionHistoryInspectSurface()`
- added `GetSelectedTemplateLaunchHistoryInspectSurface()`
- 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 selected retained guidance decision entry with lane, scope, recommended vs applied action, launch scope/budget posture, aligned launched-plan trust posture, and the current decision-weighting summary that still biases that lane and scope
- the selected retained template launch entry with template/session posture, retained aggregate analytics fragments, and retained selection provenance without reopening the scoped-stats derivation path
without scraping dashboard text blocks or reopening decision-weighting or template-analytics derivation.
## Validation
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
- passed with `0 Warning(s), 0 Error(s)`
## Next clean slice
The dashboard retained-history inspect lane now appears functionally complete. The next clean move is to pivot deliberately to the live dashboard comparison / guidance-outcome / decision-weighting inspect surface trio.