Expose dashboard run recap action control surface

This commit is contained in:
axiomlogicnexus 2026-05-10 15:50:48 +02:00
parent 00c8daf216
commit a052777bed
5 changed files with 201 additions and 4 deletions

View file

@ -12619,6 +12619,70 @@ UHyperTwistCoachDashboardWidget::GetDisplayedRunRecapDetailInspectSurface() cons
return Surface;
}
FHyperTwistTrainingCoachDashboardRunRecapActionControlInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedRunRecapActionControlInspectSurface() const
{
FHyperTwistTrainingCoachDashboardRunRecapActionControlInspectSurface Surface;
Surface.Headline = TEXT("Run recap action control");
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
&& CachedRunState.ActiveDeck.IsStructurallyValid();
const bool bHasCurrentRunRecap = bHasActiveRun
&& (CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
const bool bHasDisplayedRunRecap = bHasCurrentRunRecap || bHasRetainedRunRecap;
const bool bCanRepeatDisplayedRun = !bHasLiveAttemptTimer
&& RetainedRunRecapDeck.IsStructurallyValid()
&& (!bHasActiveRun
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
const bool bCanDismissStoredRecap = !bHasCurrentRunRecap && bHasRetainedRunRecap;
const FString DisplayedRecapSourceLabel = bHasDisplayedRunRecap
? (bHasCurrentRunRecap ? TEXT("current run") : TEXT("last completed run"))
: (bHasActiveRun ? TEXT("active run") : TEXT("none yet"));
const FString RetainedDeckLabel = RetainedRunRecapDeck.IsStructurallyValid()
? (RetainedRunRecapDeck.Title.IsEmpty()
? (RetainedRunRecapDeck.DeckId.IsEmpty() ? TEXT("n/a") : RetainedRunRecapDeck.DeckId)
: RetainedRunRecapDeck.Title)
: TEXT("n/a");
Surface.RepeatLabel = !DisplayedRepeatRunActionLabel.IsEmpty()
? DisplayedRepeatRunActionLabel
: TEXT("Repeat Run");
Surface.DismissLabel = !DisplayedDismissRecapActionLabel.IsEmpty()
? DisplayedDismissRecapActionLabel
: TEXT("Dismiss Recap");
Surface.DisplayedRecapSourceLabel = DisplayedRecapSourceLabel;
Surface.RetainedDeckLabel = RetainedDeckLabel;
Surface.RetainedSessionId = RetainedRunRecapSessionId.IsEmpty()
? TEXT("none")
: RetainedRunRecapSessionId;
Surface.bHasDisplayedRunRecap = bHasDisplayedRunRecap;
Surface.bHasCurrentRunRecap = bHasCurrentRunRecap;
Surface.bHasRetainedRunRecap = bHasRetainedRunRecap;
Surface.bHasRetainedDeck = RetainedRunRecapDeck.IsStructurallyValid();
Surface.bHasActiveRun = bHasActiveRun;
Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer;
Surface.bRepeatEnabled = bCanRepeatDisplayedRun;
Surface.bDismissEnabled = bCanDismissStoredRecap;
Surface.StatusLine = FString::Printf(
TEXT("%s: %s | %s: %s | displayed recap: %s"),
*Surface.RepeatLabel,
Surface.bRepeatEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.DismissLabel,
Surface.bDismissEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.DisplayedRecapSourceLabel);
Surface.DetailLine = FString::Printf(
TEXT("Run-recap control detail: retained deck %s | retained session %s | active run %s | live timer %s | current recap %s | retained recap %s"),
*Surface.RetainedDeckLabel,
*Surface.RetainedSessionId,
Surface.bHasActiveRun ? TEXT("yes") : TEXT("no"),
Surface.bHasLiveAttemptTimer ? TEXT("yes") : TEXT("no"),
Surface.bHasCurrentRunRecap ? TEXT("yes") : TEXT("no"),
Surface.bHasRetainedRunRecap ? TEXT("yes") : TEXT("no"));
return Surface;
}
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedActiveAttemptTimerStatusInspectSurface() const
{
@ -25743,7 +25807,12 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (RepeatRunButtonLabel != nullptr)
{
RepeatRunButtonLabel->SetText(FText::FromString(TEXT("Repeat Run")));
DisplayedRepeatRunActionLabel = TEXT("Repeat Run");
RepeatRunButtonLabel->SetText(FText::FromString(DisplayedRepeatRunActionLabel));
}
else
{
DisplayedRepeatRunActionLabel = TEXT("Repeat Run");
}
if (RepeatRunButton != nullptr)
{
@ -25751,7 +25820,12 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (DismissRecapButtonLabel != nullptr)
{
DismissRecapButtonLabel->SetText(FText::FromString(TEXT("Dismiss Recap")));
DisplayedDismissRecapActionLabel = TEXT("Dismiss Recap");
DismissRecapButtonLabel->SetText(FText::FromString(DisplayedDismissRecapActionLabel));
}
else
{
DisplayedDismissRecapActionLabel = TEXT("Dismiss Recap");
}
if (DismissRecapButton != nullptr)
{

View file

@ -883,6 +883,10 @@ public:
FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface
GetDisplayedRunRecapDetailInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardRunRecapActionControlInspectSurface
GetDisplayedRunRecapActionControlInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
GetDisplayedActiveAttemptTimerStatusInspectSurface() const;
@ -2024,6 +2028,8 @@ private:
FString DisplayedActiveRunSummaryLine;
FString DisplayedRunRecapStatusLine;
FString DisplayedRunRecapDetailLine;
FString DisplayedRepeatRunActionLabel;
FString DisplayedDismissRecapActionLabel;
FString DisplayedCurrentCasePromptLine;
FString DisplayedCurrentCaseNotationLine;
FString DisplayedAttemptTimeHintLabel;

View file

@ -13473,6 +13473,69 @@ struct FHyperTwistTrainingCoachDashboardRunRecapDetailInspectSurface
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardRunRecapActionControlInspectSurface
{
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 RepeatLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DismissLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DisplayedRecapSourceLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RetainedDeckLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RetainedSessionId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasDisplayedRunRecap = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasCurrentRunRecap = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasRetainedRunRecap = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasRetainedDeck = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasActiveRun = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasLiveAttemptTimer = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bRepeatEnabled = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bDismissEnabled = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bHasDisplayedRunRecap
|| bRepeatEnabled
|| bDismissEnabled;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
{

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 dashboard consumer lane and adds dedicated run-recap status and run-recap detail inspect surfaces over the current-or-retained recap presentation band, so gameplay/Blueprint callers can inspect the exact displayed recap lines plus the retained session/template context behind them without scraping widget text or reopening recap derivation
- the next best clean move is to stay adjacent in that same live dashboard consumer lane and expose the run-recap repeat/dismiss action control surface over the already-retained recap action labels and enablement posture
- the latest landed bounded `Phase 4` packet stays adjacent in that same live dashboard consumer lane and adds the run-recap action control inspect surface over the already-retained recap action labels and enablement posture, so gameplay/Blueprint callers can inspect the exact surfaced repeat/dismiss labels and their gating state without scraping widget button text
- the next best clean move is to stay adjacent in that same live dashboard consumer lane and expose the preferred template-launch plus recommended/follow-up preview action control surface trio over the already-derived launch/preview button labels and enablement posture
- the current execution-discipline rule that broad refactor / monolith-splitting work should not interrupt the active bounded roadmap packet unless structure is actually blocking it
## Donor portfolio phase taxonomy

View file

@ -0,0 +1,54 @@
# HyperTwist Phase 4 dashboard live run-recap action control inspect surface packet
- bounded Phase `4` dashboard-consumer slice
- date: `2026-05-10`
## Intent
Stay adjacent in the live dashboard consumer lane and expose the run-recap action controls directly to gameplay and Blueprint callers.
## Why this packet exists
`UHyperTwistCoachDashboardWidget` already displayed:
- the `Repeat Run` action label
- the `Dismiss Recap` action label
- the enablement posture behind those two recap controls
But that recap-control band still only surfaced through button labels and `SetIsEnabled` state. Callers still had to scrape widget controls to understand whether the dashboard is willing to restart the retained recap deck, whether a stored recap can be dismissed, and which retained recap source is currently gating those actions.
## What changed
- added `FHyperTwistTrainingCoachDashboardRunRecapActionControlInspectSurface`
- added `GetDisplayedRunRecapActionControlInspectSurface()`
- retained the exact displayed `Repeat Run` and `Dismiss Recap` labels inside the widget so the new surface reports the same live strings the dashboard is already presenting
- kept the packet bounded to `UHyperTwistCoachDashboardWidget` plus shared surface types, with no recap-persistence refactor and no backend continuity changes
## Files
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Public\HyperTwistTraining\HyperTwistTrainingTypes.h`
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Public\HyperTwistTraining\HyperTwistCoachDashboardWidget.h`
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Private\HyperTwistTraining\HyperTwistCoachDashboardWidget.cpp`
- `C:\HyperTwist\docs\HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md`
## Outcome
Gameplay and Blueprint callers can now inspect:
- the exact displayed `Repeat Run` label
- the exact displayed `Dismiss Recap` label
- whether repeat is currently enabled
- whether dismiss is currently enabled
- whether the gating recap is current versus retained
- whether a retained deck and retained session are currently available behind those controls
without scraping widget button text or reopening recap-control gating logic.
## Validation
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
- passed with `0 Warning(s), 0 Error(s)`
## Next clean slice
Stay on the same live dashboard consumer lane and expose the preferred template-launch plus recommended/follow-up preview action control surface trio over the already-derived launch/preview button labels and enablement posture.