Expose dashboard closure recovery status and detail surfaces

This commit is contained in:
axiomlogicnexus 2026-05-10 00:36:29 +02:00
parent 0ce8788ce5
commit 8c27560fe5
5 changed files with 322 additions and 4 deletions

View file

@ -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)
{

View file

@ -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;

View file

@ -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
{

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 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

View file

@ -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.