From 9458b71bf0a94cf11233c8e47828e5ab1581722b Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Sun, 10 May 2026 19:44:23 +0200 Subject: [PATCH] Expose dashboard decision history status and detail surfaces --- .../HyperTwistCoachDashboardWidget.cpp | 125 ++++++++++++ .../HyperTwistCoachDashboardWidget.h | 10 + .../HyperTwistTrainingTypes.h | 189 ++++++++++++++++++ ...RTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md | 4 +- ...ETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md | 53 +++++ 5 files changed, 379 insertions(+), 2 deletions(-) create mode 100644 docs/arch/HYPERTWIST_PHASE4_DASHBOARD_GUIDANCE_DECISION_HISTORY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 338c994..928cdf8 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -9479,6 +9479,129 @@ UHyperTwistCoachDashboardWidget::GetSelectedGuidanceDecisionHistoryInspectSurfac return Surface; } +FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryStatusInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceDecisionHistoryStatusInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryStatusInspectSurface Surface; + Surface.Headline = TEXT("Decision history status"); + + const FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface HistorySurface = + GetSelectedGuidanceDecisionHistoryInspectSurface(); + const FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryNavigationInspectSurface NavigationSurface = + GetDisplayedGuidanceDecisionHistoryNavigationInspectSurface(); + + Surface.StatusLine = !DisplayedGuidanceDecisionHistoryStatusLine.IsEmpty() + ? DisplayedGuidanceDecisionHistoryStatusLine + : HistorySurface.StatusLine; + Surface.SelectedEntryOrdinal = NavigationSurface.SelectedEntryOrdinal.IsEmpty() + ? TEXT("none") + : NavigationSurface.SelectedEntryOrdinal; + Surface.RecordedAtUtc = + HistorySurface.RecordedAtUtc.IsEmpty() ? TEXT("n/a") : HistorySurface.RecordedAtUtc; + Surface.GuidanceLaneLabel = !HistorySurface.GuidanceLaneLabel.IsEmpty() + ? HistorySurface.GuidanceLaneLabel + : (NavigationSurface.GuidanceLaneLabel.IsEmpty() + ? TEXT("none") + : NavigationSurface.GuidanceLaneLabel); + Surface.ScopeLabel = !HistorySurface.ScopeLabel.IsEmpty() + ? HistorySurface.ScopeLabel + : (NavigationSurface.ScopeLabel.IsEmpty() ? TEXT("n/a") : NavigationSurface.ScopeLabel); + Surface.RecommendedActionLabel = !HistorySurface.RecommendedActionLabel.IsEmpty() + ? HistorySurface.RecommendedActionLabel + : (NavigationSurface.RecommendedActionLabel.IsEmpty() + ? TEXT("none") + : NavigationSurface.RecommendedActionLabel); + Surface.AppliedActionLabel = !HistorySurface.AppliedActionLabel.IsEmpty() + ? HistorySurface.AppliedActionLabel + : (NavigationSurface.AppliedActionLabel.IsEmpty() + ? TEXT("none") + : NavigationSurface.AppliedActionLabel); + Surface.WeightingStatusLine = !NavigationSurface.WeightingStatusLine.IsEmpty() + ? NavigationSurface.WeightingStatusLine + : (HistorySurface.WeightingStatusLine.IsEmpty() + ? TEXT("n/a") + : HistorySurface.WeightingStatusLine); + Surface.LastAppliedActionLabel = !NavigationSurface.LastAppliedActionLabel.IsEmpty() + ? NavigationSurface.LastAppliedActionLabel + : (HistorySurface.LastAppliedActionLabel.IsEmpty() + ? TEXT("none") + : HistorySurface.LastAppliedActionLabel); + Surface.SelectedEntryIndex = HistorySurface.SelectedEntryIndex; + Surface.HistoryEntryCount = HistorySurface.HistoryEntryCount; + Surface.MatchingDecisionCount = HistorySurface.MatchingDecisionCount; + Surface.bHasSelectedEntry = HistorySurface.bHasSelectedEntry; + Surface.bSelectedEntryIsLatest = NavigationSurface.bSelectedEntryIsLatest; + Surface.bHasWeighting = NavigationSurface.bHasWeighting || HistorySurface.bHasWeighting; + Surface.bClosedLoopIdleActionability = + NavigationSurface.bClosedLoopIdleActionability + || HistorySurface.bClosedLoopIdleActionability; + return Surface; +} + +FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryDetailInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceDecisionHistoryDetailInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryDetailInspectSurface Surface; + Surface.Headline = TEXT("Decision history detail"); + + const FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface HistorySurface = + GetSelectedGuidanceDecisionHistoryInspectSurface(); + + Surface.DetailLine = !DisplayedGuidanceDecisionHistoryDetailLine.IsEmpty() + ? DisplayedGuidanceDecisionHistoryDetailLine + : HistorySurface.DetailLine; + Surface.WeightingDetailLine = HistorySurface.WeightingDetailLine.IsEmpty() + ? TEXT("n/a") + : HistorySurface.WeightingDetailLine; + Surface.SourceSessionId = + HistorySurface.SourceSessionId.IsEmpty() ? TEXT("n/a") : HistorySurface.SourceSessionId; + Surface.BriefHeadline = + HistorySurface.BriefHeadline.IsEmpty() ? TEXT("n/a") : HistorySurface.BriefHeadline; + Surface.SelectedCaseId = + HistorySurface.SelectedCaseId.IsEmpty() ? TEXT("n/a") : HistorySurface.SelectedCaseId; + Surface.LaunchBudgetReasonLine = HistorySurface.LaunchBudgetReasonLine.IsEmpty() + ? TEXT("n/a") + : HistorySurface.LaunchBudgetReasonLine; + Surface.BaseActionLabel = + HistorySurface.BaseActionLabel.IsEmpty() ? TEXT("none") : HistorySurface.BaseActionLabel; + Surface.WeightedActionLabel = HistorySurface.WeightedActionLabel.IsEmpty() + ? TEXT("none") + : HistorySurface.WeightedActionLabel; + Surface.LastAppliedActionLabel = HistorySurface.LastAppliedActionLabel.IsEmpty() + ? TEXT("none") + : HistorySurface.LastAppliedActionLabel; + Surface.SelectedEntryIndex = HistorySurface.SelectedEntryIndex; + Surface.HistoryEntryCount = HistorySurface.HistoryEntryCount; + Surface.MatchingDecisionCount = HistorySurface.MatchingDecisionCount; + Surface.RepeatSelectedCaseCount = HistorySurface.RepeatSelectedCaseCount; + Surface.RepeatPreviewDeckCount = HistorySurface.RepeatPreviewDeckCount; + Surface.BroadenPreviewDeckCount = HistorySurface.BroadenPreviewDeckCount; + Surface.RedirectCoachGuidanceCount = HistorySurface.RedirectCoachGuidanceCount; + Surface.CompletedAttemptCount = HistorySurface.CompletedAttemptCount; + Surface.TotalMistakes = HistorySurface.TotalMistakes; + Surface.LaunchedCaseCount = HistorySurface.LaunchedCaseCount; + Surface.ReferenceCaseCount = HistorySurface.ReferenceCaseCount; + Surface.SuccessRate = HistorySurface.SuccessRate; + Surface.AverageSuccessRate = HistorySurface.AverageSuccessRate; + Surface.AverageLaunchCaseCount = HistorySurface.AverageLaunchCaseCount; + Surface.BroadenedLaunchAverageSuccessRate = + HistorySurface.BroadenedLaunchAverageSuccessRate; + Surface.TightenedLaunchAverageSuccessRate = + HistorySurface.TightenedLaunchAverageSuccessRate; + Surface.bHasSelectedEntry = HistorySurface.bHasSelectedEntry; + Surface.bHasWeighting = HistorySurface.bHasWeighting; + Surface.bSingleCaseScope = HistorySurface.bSingleCaseScope; + Surface.bBroadenedLaunchScope = HistorySurface.bBroadenedLaunchScope; + Surface.bTightenedLaunchScope = HistorySurface.bTightenedLaunchScope; + Surface.bHasWeightingOverride = HistorySurface.bHasWeightingOverride; + Surface.bUsedClosureHistorySignal = HistorySurface.bUsedClosureHistorySignal; + Surface.bUsedDeferredOverflowSignal = HistorySurface.bUsedDeferredOverflowSignal; + Surface.bUsedReliableAlignedPlanOutcomeSignal = + HistorySurface.bUsedReliableAlignedPlanOutcomeSignal; + Surface.bClosedLoopIdleActionability = HistorySurface.bClosedLoopIdleActionability; + return Surface; +} + FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryNavigationInspectSurface UHyperTwistCoachDashboardWidget::GetDisplayedGuidanceDecisionHistoryNavigationInspectSurface() const { @@ -26480,10 +26603,12 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() { GuidanceDecisionHistoryHeaderTextBlock->SetText(FText::FromString(TEXT("[Decision History]"))); } + DisplayedGuidanceDecisionHistoryStatusLine = GuidanceDecisionHistoryStatusLine; if (GuidanceDecisionHistoryStatusTextBlock != nullptr) { GuidanceDecisionHistoryStatusTextBlock->SetText(FText::FromString(GuidanceDecisionHistoryStatusLine)); } + DisplayedGuidanceDecisionHistoryDetailLine = GuidanceDecisionHistoryDetailLine; if (GuidanceDecisionHistoryDetailTextBlock != nullptr) { GuidanceDecisionHistoryDetailTextBlock->SetText(FText::FromString(GuidanceDecisionHistoryDetailLine)); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index 43b50f1..5dc2abc 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -807,6 +807,14 @@ public: FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryInspectSurface GetSelectedGuidanceDecisionHistoryInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryStatusInspectSurface + GetDisplayedGuidanceDecisionHistoryStatusInspectSurface() const; + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryDetailInspectSurface + GetDisplayedGuidanceDecisionHistoryDetailInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryNavigationInspectSurface GetDisplayedGuidanceDecisionHistoryNavigationInspectSurface() const; @@ -2138,6 +2146,8 @@ private: FString DisplayedClosureRecoveryDetailLine; FString DisplayedHandoffHistoryStatusLine; FString DisplayedHandoffHistoryDetailLine; + FString DisplayedGuidanceDecisionHistoryStatusLine; + FString DisplayedGuidanceDecisionHistoryDetailLine; FString DisplayedPreviousQueueNavigationLabel; FString DisplayedStartSelectedQueueActionLabel; FString DisplayedNextQueueNavigationLabel; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index be0d008..57e39f3 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -10466,6 +10466,195 @@ struct FHyperTwistTrainingCoachDashboardHandoffHistoryInspectSurface } }; +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryStatusInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedEntryOrdinal; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString RecordedAtUtc; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GuidanceLaneLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ScopeLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString RecommendedActionLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString AppliedActionLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString WeightingStatusLine; + + 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") + bool bHasSelectedEntry = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSelectedEntryIsLatest = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasWeighting = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bClosedLoopIdleActionability = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !WeightingStatusLine.IsEmpty() + || bHasSelectedEntry + || bHasWeighting + || HistoryEntryCount > 0; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryDetailInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString WeightingDetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SourceSessionId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString BriefHeadline; + + 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 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") + 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 bClosedLoopIdleActionability = false; + + bool IsStructurallyValid() const + { + return !DetailLine.IsEmpty() + || !WeightingDetailLine.IsEmpty() + || bHasSelectedEntry + || bHasWeighting + || HistoryEntryCount > 0; + } +}; + USTRUCT(BlueprintType) struct FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryNavigationInspectSurface { diff --git a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md index 918925a..4d8f7f7 100644 --- a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md +++ b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md @@ -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 adjacent in that same retained-history dashboard lane and adds the dedicated handoff history status/detail inspect pair over the exact displayed retained-history lines already shown by the widget, so gameplay/Blueprint callers can inspect the current retained handoff-history text band directly without scraping text blocks or routing only through the broader selected-history and navigation surfaces - - the retained handoff-history band is now functionally complete enough to stop widening it by drift; the next best clean move is to stay in that same retained-history dashboard neighborhood and expose the displayed guidance-decision history status/detail pair over the current guidance-decision-history text band + - the latest landed bounded `Phase 4` packet stays adjacent in that same retained-history dashboard lane and adds the dedicated guidance-decision history status/detail inspect pair over the exact displayed retained-history lines already shown by the widget, so gameplay/Blueprint callers can inspect the current retained decision-history text band directly without scraping text blocks or routing only through the broader selected-history and navigation surfaces + - the retained guidance-decision-history band is now functionally complete enough to stop widening it by drift; the next best clean move is to stay in that same retained-history dashboard neighborhood and expose the displayed method-drill follow-up history status/detail pair over the current method-drill-follow-up-history text band - 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 diff --git a/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_GUIDANCE_DECISION_HISTORY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_GUIDANCE_DECISION_HISTORY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md new file mode 100644 index 0000000..87f8367 --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_GUIDANCE_DECISION_HISTORY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md @@ -0,0 +1,53 @@ +# HyperTwist Phase 4 dashboard guidance decision history status detail inspect surface packet + +- bounded Phase `4` dashboard-consumer slice +- date: `2026-05-10` + +## Intent + +Stay adjacent in the retained-history dashboard lane and expose the dedicated guidance-decision-history text band directly to gameplay and Blueprint callers. + +## Why this packet exists + +`UHyperTwistCoachDashboardWidget` already displayed: + +- the current `Decision history` status line +- the current `Decision history` detail line + +But those two lines only surfaced through `GuidanceDecisionHistoryStatusTextBlock` and `GuidanceDecisionHistoryDetailTextBlock`. Callers could inspect the selected retained decision entry and the prev/next navigation posture separately, but there was still no dedicated inspect surface for the exact retained-history text band the dashboard was already presenting. + +## What changed + +- added `FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryStatusInspectSurface` +- added `FHyperTwistTrainingCoachDashboardGuidanceDecisionHistoryDetailInspectSurface` +- added `GetDisplayedGuidanceDecisionHistoryStatusInspectSurface()` +- added `GetDisplayedGuidanceDecisionHistoryDetailInspectSurface()` +- retained the exact displayed guidance-decision-history status/detail lines inside the widget so the new surfaces report the same live strings the dashboard is already presenting +- composed both surfaces over the already-landed selected-guidance-decision-history and guidance-decision-history-navigation surfaces so the packet stayed bounded and reused the same retained-history derivation + +## 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 guidance-decision-history status line +- the exact displayed guidance-decision-history detail line +- selected retained entry ordinal, lane, scope, recommended/applied action, and weighting summary context +- selected session/brief/case/budget context plus retained decision-weighting detail and launch-success posture + +without scraping widget text blocks or stitching together the selected-history and navigation wrappers manually. + +## Validation + +- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln` + - passed with `0 Warning(s), 0 Error(s)` + +## Next clean slice + +Treat the retained guidance-decision-history band as functionally complete enough and stay in the same retained-history dashboard neighborhood to expose the displayed method-drill follow-up history status/detail pair over the current method-drill-follow-up-history text band.