From 8c27560fe5281e8e28aab76911dfd8f887f7ae2e Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Sun, 10 May 2026 00:36:29 +0200 Subject: [PATCH] Expose dashboard closure recovery status and detail surfaces --- .../HyperTwistCoachDashboardWidget.cpp | 142 +++++++++++++++++- .../HyperTwistCoachDashboardWidget.h | 10 ++ .../HyperTwistTrainingTypes.h | 118 +++++++++++++++ ...RTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md | 4 +- ...ETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md | 52 +++++++ 5 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_CLOSURE_RECOVERY_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 c437ab9..ea2c2b7 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -11880,6 +11880,142 @@ UHyperTwistCoachDashboardWidget::GetDisplayedSchedulePolicyFrictionInspectSurfac return Surface; } +FHyperTwistTrainingCoachDashboardClosureRecoveryStatusInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedClosureRecoveryStatusInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardClosureRecoveryStatusInspectSurface Surface; + Surface.Headline = TEXT("Closure recovery status"); + + Surface.HistoricalFollowUpContinuationCount = + CachedCoachSchedulePolicySummary.HistoricalFollowUpContinuationCount; + Surface.HistoricalBorderlineFollowUpSuppressionCount = + CachedCoachSchedulePolicySummary.HistoricalBorderlineFollowUpSuppressionCount; + Surface.bHasClosureRecoveryHistory = + Surface.HistoricalFollowUpContinuationCount > 0 + || Surface.HistoricalBorderlineFollowUpSuppressionCount > 0; + Surface.PreferredGuidanceLane = CachedCoachPanelState.PreferredGuidanceLane; + Surface.GuidanceLaneLabel = HyperTwistCoachDashboardWidgetInternal::DescribeGuidanceLane( + Surface.PreferredGuidanceLane); + Surface.ClosurePolicyLine = CachedCoachSchedulePolicySummary.ClosurePolicyLine.IsEmpty() + ? TEXT("n/a") + : CachedCoachSchedulePolicySummary.ClosurePolicyLine; + Surface.ClosureRecoveryHistoryLabel = + Surface.HistoricalFollowUpContinuationCount + > Surface.HistoricalBorderlineFollowUpSuppressionCount + ? TEXT("follow-up continuity history is dominant") + : (Surface.HistoricalBorderlineFollowUpSuppressionCount + > Surface.HistoricalFollowUpContinuationCount + ? TEXT("recommended-side suppression history is dominant") + : (Surface.bHasClosureRecoveryHistory + ? TEXT("retained closure history is balanced") + : TEXT("no retained closure history"))); + + const FHyperTwistCoachSignal* ClosureRecoverySignal = CachedCoachSignals.FindByPredicate( + [](const FHyperTwistCoachSignal& Signal) + { + return Signal.SignalId == TEXT("closure_history_follow_up_continuation") + || Signal.SignalId == TEXT("closure_history_recommended_suppression"); + }); + Surface.bHasActiveSignal = ClosureRecoverySignal != nullptr; + Surface.bActiveSignalPromoted = + ClosureRecoverySignal != nullptr + && CachedCoachBrief.Signals.Num() > 0 + && CachedCoachBrief.Signals[0].SignalId == ClosureRecoverySignal->SignalId; + Surface.ActiveSignalId = + ClosureRecoverySignal != nullptr && !ClosureRecoverySignal->SignalId.IsEmpty() + ? ClosureRecoverySignal->SignalId + : TEXT("none"); + Surface.ActiveSignalHeadline = + ClosureRecoverySignal != nullptr && !ClosureRecoverySignal->Headline.IsEmpty() + ? ClosureRecoverySignal->Headline + : TEXT("n/a"); + Surface.ActiveSignalPriorityLabel = ClosureRecoverySignal != nullptr + ? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName( + ClosureRecoverySignal->Priority) + : TEXT("n/a"); + Surface.ActiveSignalScore = ClosureRecoverySignal != nullptr + ? ClosureRecoverySignal->Score + : 0.0f; + Surface.StatusLine = !DisplayedClosureRecoveryStatusLine.IsEmpty() + ? DisplayedClosureRecoveryStatusLine + : (ClosureRecoverySignal != nullptr + ? FString::Printf( + TEXT("Closure recovery: %s | promoted: %s | headline: %s | priority: %s | score %.1f"), + *Surface.ClosureRecoveryHistoryLabel, + Surface.bActiveSignalPromoted ? TEXT("yes") : TEXT("no"), + *Surface.ActiveSignalHeadline, + *Surface.ActiveSignalPriorityLabel, + Surface.ActiveSignalScore) + : (Surface.bHasClosureRecoveryHistory + ? FString::Printf( + TEXT("Closure recovery: retained history is present without an active closure-history signal | policy: %s"), + *Surface.ClosurePolicyLine) + : TEXT("Closure recovery: no retained closure-recovery history is recorded yet."))); + return Surface; +} + +FHyperTwistTrainingCoachDashboardClosureRecoveryDetailInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedClosureRecoveryDetailInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardClosureRecoveryDetailInspectSurface Surface; + Surface.Headline = TEXT("Closure recovery detail"); + + Surface.HistoricalFollowUpContinuationCount = + CachedCoachSchedulePolicySummary.HistoricalFollowUpContinuationCount; + Surface.HistoricalBorderlineFollowUpSuppressionCount = + CachedCoachSchedulePolicySummary.HistoricalBorderlineFollowUpSuppressionCount; + Surface.bHasClosureRecoveryHistory = + Surface.HistoricalFollowUpContinuationCount > 0 + || Surface.HistoricalBorderlineFollowUpSuppressionCount > 0; + Surface.bFollowUpContinuationFromRecoveryHistory = + CachedCoachSchedulePolicySummary.bFollowUpContinuationFromRecoveryHistory; + Surface.bBorderlineFollowUpSuppressedByRecoveryHistory = + CachedCoachSchedulePolicySummary.bBorderlineFollowUpSuppressedByRecoveryHistory; + Surface.PreferredGuidanceLane = CachedCoachPanelState.PreferredGuidanceLane; + Surface.GuidanceLaneLabel = HyperTwistCoachDashboardWidgetInternal::DescribeGuidanceLane( + Surface.PreferredGuidanceLane); + Surface.PreferredGuidanceSourceLabel = + CachedCoachPanelState.PreferredGuidanceSourceLabel.IsEmpty() + ? TEXT("none") + : CachedCoachPanelState.PreferredGuidanceSourceLabel; + Surface.PreferredGuidanceSourceDescription = + HyperTwistCoachDashboardWidgetInternal::DescribeCoachMemorySourceLabel( + CachedCoachPanelState.PreferredGuidanceSourceLabel); + Surface.ClosurePolicyLine = CachedCoachSchedulePolicySummary.ClosurePolicyLine.IsEmpty() + ? TEXT("n/a") + : CachedCoachSchedulePolicySummary.ClosurePolicyLine; + + const FHyperTwistCoachSignal* ClosureRecoverySignal = CachedCoachSignals.FindByPredicate( + [](const FHyperTwistCoachSignal& Signal) + { + return Signal.SignalId == TEXT("closure_history_follow_up_continuation") + || Signal.SignalId == TEXT("closure_history_recommended_suppression"); + }); + Surface.bHasActiveSignal = ClosureRecoverySignal != nullptr; + Surface.ActiveSignalId = + ClosureRecoverySignal != nullptr && !ClosureRecoverySignal->SignalId.IsEmpty() + ? ClosureRecoverySignal->SignalId + : TEXT("none"); + Surface.ActiveSignalDetail = + ClosureRecoverySignal != nullptr && !ClosureRecoverySignal->Detail.IsEmpty() + ? ClosureRecoverySignal->Detail + : TEXT(""); + Surface.DetailLine = !DisplayedClosureRecoveryDetailLine.IsEmpty() + ? DisplayedClosureRecoveryDetailLine + : FString::Printf( + TEXT("Policy: %s | keep %d | suppress %d | continuation active: %s | borderline suppression active: %s | guidance lane: %s | source: %s%s%s"), + *Surface.ClosurePolicyLine, + Surface.HistoricalFollowUpContinuationCount, + Surface.HistoricalBorderlineFollowUpSuppressionCount, + Surface.bFollowUpContinuationFromRecoveryHistory ? TEXT("yes") : TEXT("no"), + Surface.bBorderlineFollowUpSuppressedByRecoveryHistory ? TEXT("yes") : TEXT("no"), + *Surface.GuidanceLaneLabel, + *Surface.PreferredGuidanceSourceDescription, + ClosureRecoverySignal != nullptr ? TEXT(" || Signal detail: ") : TEXT(""), + ClosureRecoverySignal != nullptr ? *Surface.ActiveSignalDetail : TEXT("")); + return Surface; +} + FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface UHyperTwistCoachDashboardWidget::GetDisplayedLastAttemptReviewSummaryInspectSurface() const { @@ -24398,6 +24534,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() ? *ClosureRecoverySignal->Detail : TEXT("") ); + DisplayedClosureRecoveryStatusLine = ClosureRecoveryStatusLine; + DisplayedClosureRecoveryDetailLine = ClosureRecoveryDetailLine; const FHyperTwistCoachDashboardClosureRecoveryEntry* SelectedClosureRecoveryEntry = SelectedClosureRecoveryIndex >= 0 && SelectedClosureRecoveryIndex < ClosureRecoveryHistoryEntries.Num() @@ -24457,11 +24595,11 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() } if (ClosureRecoveryStatusTextBlock != nullptr) { - ClosureRecoveryStatusTextBlock->SetText(FText::FromString(ClosureRecoveryStatusLine)); + ClosureRecoveryStatusTextBlock->SetText(FText::FromString(DisplayedClosureRecoveryStatusLine)); } if (ClosureRecoveryDetailTextBlock != nullptr) { - ClosureRecoveryDetailTextBlock->SetText(FText::FromString(ClosureRecoveryDetailLine)); + ClosureRecoveryDetailTextBlock->SetText(FText::FromString(DisplayedClosureRecoveryDetailLine)); } if (ClosureRecoveryHistoryHeaderTextBlock != nullptr) { diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index e60625b..c6eaa14 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -883,6 +883,14 @@ public: FHyperTwistTrainingCoachDashboardSchedulePolicyFrictionInspectSurface GetDisplayedSchedulePolicyFrictionInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardClosureRecoveryStatusInspectSurface + GetDisplayedClosureRecoveryStatusInspectSurface() const; + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardClosureRecoveryDetailInspectSurface + GetDisplayedClosureRecoveryDetailInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface GetDisplayedLastAttemptReviewSummaryInspectSurface() const; @@ -1977,6 +1985,8 @@ private: FString DisplayedSelectedQueueEntryDetailLine; FString DisplayedScheduleStatusLine; FString DisplayedSchedulePolicyLine; + FString DisplayedClosureRecoveryStatusLine; + FString DisplayedClosureRecoveryDetailLine; 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 71dc4d3..5948c18 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -11731,6 +11731,124 @@ struct FHyperTwistTrainingCoachDashboardSchedulePolicyFrictionInspectSurface } }; +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardClosureRecoveryStatusInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ClosureRecoveryHistoryLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ClosurePolicyLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GuidanceLaneLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveSignalId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveSignalHeadline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveSignalPriorityLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 HistoricalFollowUpContinuationCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 HistoricalBorderlineFollowUpSuppressionCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + float ActiveSignalScore = 0.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + EHyperTwistTrainingCoachGuidanceLane PreferredGuidanceLane = + EHyperTwistTrainingCoachGuidanceLane::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasClosureRecoveryHistory = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasActiveSignal = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bActiveSignalPromoted = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || bHasClosureRecoveryHistory + || bHasActiveSignal; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardClosureRecoveryDetailInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ClosurePolicyLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GuidanceLaneLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString PreferredGuidanceSourceLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString PreferredGuidanceSourceDescription; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveSignalId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveSignalDetail; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 HistoricalFollowUpContinuationCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 HistoricalBorderlineFollowUpSuppressionCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + EHyperTwistTrainingCoachGuidanceLane PreferredGuidanceLane = + EHyperTwistTrainingCoachGuidanceLane::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasClosureRecoveryHistory = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bFollowUpContinuationFromRecoveryHistory = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bBorderlineFollowUpSuppressedByRecoveryHistory = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasActiveSignal = false; + + bool IsStructurallyValid() const + { + return !DetailLine.IsEmpty() + || bHasClosureRecoveryHistory + || bHasActiveSignal; + } +}; + USTRUCT(BlueprintType) struct FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface { diff --git a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md index 518c7e0..89a132b 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 on that same live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds schedule horizon status and schedule policy / friction inspect surfaces over already-derived live dashboard schedule presentation state, so gameplay/Blueprint callers can inspect the live horizon posture, queue-window summary, policy/friction line, and reschedule/closure posture without scraping widget text or reopening schedule derivation - - the next clean move is to stay on that same live dashboard guidance-consumer lane and land the closure-recovery live status and closure-recovery detail inspect surface pair rather than drifting back into backend continuity or reopening the already-complete retained-history seam + - the latest landed bounded `Phase 4` packet stays on that same live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds closure-recovery live status and closure-recovery detail inspect surfaces over already-derived live dashboard closure presentation state, so gameplay/Blueprint callers can inspect the live closure-history dominance posture, active closure-history signal posture, and closure-policy/source detail without scraping widget text or reopening schedule/coach derivation + - the next clean move is to stay on that same live dashboard guidance-consumer lane and expose the remaining closure-recovery history navigation control surface over already-retained history state rather than drifting back into backend continuity or reopening the already-complete retained-history inspect seam - the current execution-discipline rule that broad refactor / monolith-splitting work should not interrupt the active bounded roadmap packet unless structure is actually blocking it ## Donor portfolio phase taxonomy diff --git a/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_CLOSURE_RECOVERY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_CLOSURE_RECOVERY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md new file mode 100644 index 0000000..01845d3 --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_CLOSURE_RECOVERY_STATUS_DETAIL_INSPECT_SURFACE_PACKET_2026-05-10.md @@ -0,0 +1,52 @@ +# HyperTwist Phase 4 dashboard live closure-recovery status and detail inspect surface packet + +- bounded Phase `4` dashboard-consumer slice +- date: `2026-05-10` + +## Intent + +Stay on the deliberate live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and expose the remaining live closure-recovery presentation state directly to gameplay and Blueprint callers. + +## Why this packet exists + +The dashboard already derived: + +- the live closure-recovery status line +- the live closure-recovery detail line + +But that state still only surfaced through widget text blocks. Callers still had to scrape dashboard text to inspect whether retained closure history is dominant, whether an active closure-history signal is currently promoted, and what policy/source detail is driving the current closure posture. + +## What changed + +- added `FHyperTwistTrainingCoachDashboardClosureRecoveryStatusInspectSurface` +- added `FHyperTwistTrainingCoachDashboardClosureRecoveryDetailInspectSurface` +- added `GetDisplayedClosureRecoveryStatusInspectSurface()` +- added `GetDisplayedClosureRecoveryDetailInspectSurface()` +- retained the exact displayed closure-recovery status and detail lines inside the widget so the new inspect surfaces report the same live strings the dashboard is already presenting +- 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 live closure-history dominance posture and whether an active closure-history signal exists +- the live closure-history signal id, headline, priority posture, and promoted-vs-background status +- the live closure policy line, retained keep-vs-suppress counts, guidance lane, and source/detail context + +without scraping dashboard text blocks or reopening schedule/coach derivation. + +## Validation + +- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln` + - passed with `0 Warning(s), 0 Error(s)` + +## Next clean slice + +Stay on the same live dashboard guidance-consumer lane and expose the remaining closure-recovery history navigation control surface over already-retained history state.