Expose dashboard guidance preview launch action control surface

This commit is contained in:
axiomlogicnexus 2026-05-10 16:51:14 +02:00
parent 47cf3bb7fd
commit 018a8ff2ac
5 changed files with 240 additions and 4 deletions

View file

@ -10650,6 +10650,106 @@ UHyperTwistCoachDashboardWidget::GetDisplayedGuidancePreviewCaseNavigationInspec
return Surface;
}
FHyperTwistTrainingCoachDashboardGuidancePreviewLaunchActionControlInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedGuidancePreviewLaunchActionControlInspectSurface() const
{
FHyperTwistTrainingCoachDashboardGuidancePreviewLaunchActionControlInspectSurface Surface;
Surface.Headline = TEXT("Preview launch action control");
const auto BuildPreviewLaneLabel = [](const EHyperTwistCoachDashboardGuidancePreviewLane Lane) -> FString
{
return Lane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
? TEXT("recommended")
: (Lane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
? TEXT("follow-up")
: TEXT("none"));
};
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
&& CachedRunState.ActiveDeck.IsStructurallyValid();
const FHyperTwistTrainingDeck* ActivePreviewDeck = GetActiveGuidancePreviewDeck();
const FHyperTwistTrainingCase* SelectedGuidancePreviewCase =
ActivePreviewDeck != nullptr
&& SelectedGuidancePreviewCaseIndex >= 0
&& SelectedGuidancePreviewCaseIndex < ActivePreviewDeck->Cases.Num()
? &ActivePreviewDeck->Cases[SelectedGuidancePreviewCaseIndex]
: nullptr;
const bool bCanStartPreviewDeck =
!bHasLiveAttemptTimer
&& !bHasActiveRun
&& ActivePreviewDeck != nullptr
&& ActivePreviewDeck->IsStructurallyValid();
const bool bCanStartPreviewCase =
bCanStartPreviewDeck && SelectedGuidancePreviewCase != nullptr;
Surface.StartPreviewDeckLabel = !DisplayedStartPreviewDeckActionLabel.IsEmpty()
? DisplayedStartPreviewDeckActionLabel
: TEXT("Start Preview Deck");
Surface.StartSelectedPreviewCaseLabel = !DisplayedStartPreviewCaseActionLabel.IsEmpty()
? DisplayedStartPreviewCaseActionLabel
: TEXT("Start Selected Preview Case");
Surface.ActivePreviewLaneLabel = BuildPreviewLaneLabel(ActiveGuidancePreviewLane);
Surface.DeckLabel =
ActivePreviewDeck != nullptr
? (ActivePreviewDeck->Title.IsEmpty() ? ActivePreviewDeck->DeckId : ActivePreviewDeck->Title)
: TEXT("n/a");
Surface.SelectedCaseId =
SelectedGuidancePreviewCase != nullptr && !SelectedGuidancePreviewCase->CaseId.IsEmpty()
? SelectedGuidancePreviewCase->CaseId
: TEXT("n/a");
Surface.SelectedCasePromptLabel =
SelectedGuidancePreviewCase != nullptr
&& !SelectedGuidancePreviewCase->PromptLabel.IsEmpty()
? SelectedGuidancePreviewCase->PromptLabel
: TEXT("n/a");
Surface.SelectedCaseOrdinal =
SelectedGuidancePreviewCase != nullptr && ActivePreviewDeck != nullptr
? FString::Printf(TEXT("%d/%d"), SelectedGuidancePreviewCaseIndex + 1, ActivePreviewDeck->Cases.Num())
: TEXT("none");
Surface.SelectedCaseIndex = SelectedGuidancePreviewCaseIndex;
Surface.TotalCaseCount = ActivePreviewDeck != nullptr ? ActivePreviewDeck->Cases.Num() : 0;
Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer;
Surface.bHasActiveRun = bHasActiveRun;
Surface.bHasActivePreviewDeck = ActivePreviewDeck != nullptr;
Surface.bHasSelectedCase = SelectedGuidancePreviewCase != nullptr;
Surface.bStartPreviewDeckEnabled = bCanStartPreviewDeck;
Surface.bStartSelectedPreviewCaseEnabled = bCanStartPreviewCase;
const bool bQueueRecoveryMemorySource =
HyperTwistCoachDashboardWidgetInternal::IsQueueRecoveryMemorySource(
CachedCoachPanelState.PreferredGuidanceSourceLabel);
Surface.bClosedLoopIdleDashboard =
IsCoachLoopActionabilityClosed()
&& (
bQueueRecoveryMemorySource
|| !CachedCoachPanelState.PreferredGuidanceSourceLabel.IsEmpty()
|| DisplayedCoachHandoffRecommendationKind != EHyperTwistTrainingCoachHandoffKind::None);
Surface.StatusLine = FString::Printf(
TEXT("%s: %s | %s: %s | lane %s | deck %s"),
*Surface.StartPreviewDeckLabel,
Surface.bStartPreviewDeckEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.StartSelectedPreviewCaseLabel,
Surface.bStartSelectedPreviewCaseEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.ActivePreviewLaneLabel,
*Surface.DeckLabel);
Surface.DetailLine = FString::Printf(
TEXT("Preview launch detail: selected %s | case %s | prompt %s | live timer %s | active run %s"),
*Surface.SelectedCaseOrdinal,
*Surface.SelectedCaseId,
*Surface.SelectedCasePromptLabel,
Surface.bHasLiveAttemptTimer ? TEXT("yes") : TEXT("no"),
Surface.bHasActiveRun ? TEXT("yes") : TEXT("no"));
if (Surface.bClosedLoopIdleDashboard)
{
Surface.StatusLine =
TEXT("Preview launch control: no active guidance preview remains in the closed-loop idle state.");
Surface.DetailLine =
TEXT("Preview launch detail: retained coach memory remains inspectable, but live preview-deck and preview-case launch actions are inactive.");
}
return Surface;
}
FHyperTwistTrainingCoachDashboardMethodDrillDiagnosticsInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedMethodDrillDiagnosticsInspectSurface() const
{
@ -26477,7 +26577,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (StartPreviewDeckButtonLabel != nullptr)
{
StartPreviewDeckButtonLabel->SetText(FText::FromString(TEXT("Start Preview Deck")));
DisplayedStartPreviewDeckActionLabel = TEXT("Start Preview Deck");
StartPreviewDeckButtonLabel->SetText(FText::FromString(
DisplayedStartPreviewDeckActionLabel));
}
if (StartPreviewDeckButton != nullptr)
{
@ -26485,7 +26587,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (StartPreviewCaseButtonLabel != nullptr)
{
StartPreviewCaseButtonLabel->SetText(FText::FromString(TEXT("Start Selected Preview Case")));
DisplayedStartPreviewCaseActionLabel = TEXT("Start Selected Preview Case");
StartPreviewCaseButtonLabel->SetText(FText::FromString(
DisplayedStartPreviewCaseActionLabel));
}
if (StartPreviewCaseButton != nullptr)
{

View file

@ -835,6 +835,10 @@ public:
FHyperTwistTrainingCoachDashboardGuidancePreviewCaseNavigationInspectSurface
GetDisplayedGuidancePreviewCaseNavigationInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardGuidancePreviewLaunchActionControlInspectSurface
GetDisplayedGuidancePreviewLaunchActionControlInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardMethodDrillDiagnosticsInspectSurface
GetDisplayedMethodDrillDiagnosticsInspectSurface() const;
@ -2070,6 +2074,8 @@ private:
FString DisplayedTimerStatusLine;
FString DisplayedPreviewRecommendedActionLabel;
FString DisplayedPreviewFollowUpActionLabel;
FString DisplayedStartPreviewDeckActionLabel;
FString DisplayedStartPreviewCaseActionLabel;
FString DisplayedRecommendedDeckPreviewLine;
FString DisplayedFollowUpDeckPreviewLine;
FString DisplayedMethodDrillDiagnosticsStatusLine;

View file

@ -11370,6 +11370,79 @@ struct FHyperTwistTrainingCoachDashboardGuidancePreviewCaseNavigationInspectSurf
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardGuidancePreviewLaunchActionControlInspectSurface
{
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 StartPreviewDeckLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString StartSelectedPreviewCaseLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActivePreviewLaneLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DeckLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedCaseId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedCasePromptLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedCaseOrdinal;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 SelectedCaseIndex = INDEX_NONE;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 TotalCaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasLiveAttemptTimer = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasActiveRun = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasActivePreviewDeck = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelectedCase = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bClosedLoopIdleDashboard = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bStartPreviewDeckEnabled = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bStartSelectedPreviewCaseEnabled = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bHasActivePreviewDeck
|| bHasSelectedCase
|| bStartPreviewDeckEnabled
|| bStartSelectedPreviewCaseEnabled;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardGuidanceRationaleInspectSurface
{

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 adjacent in that same live dashboard consumer lane and adds the guidance preview case navigation control surface over the already-derived `Prev Guidance Case` / `Next Guidance Case` labels and enablement posture, so gameplay/Blueprint callers can inspect the exact surfaced preview-case navigation 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 preview-deck plus start-selected-preview-case action control pair over the already-derived launch button labels and enablement posture
- the latest landed bounded `Phase 4` packet stays adjacent in that same live dashboard consumer lane and adds the guidance preview launch action control surface over the already-derived `Start Preview Deck` / `Start Selected Preview Case` labels and enablement posture, so gameplay/Blueprint callers can inspect the exact surfaced preview-launch labels, selected-case launch context, and gating state without scraping widget button text
- the preview-control seam is now functionally complete enough to stop widening it by drift; the next best clean move is to pivot slightly earlier in that same live dashboard consumer lane and expose the dedicated template-launch status/detail inspect pair over the exact displayed template-launch lines already cached in the widget
- 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,53 @@
# HyperTwist Phase 4 dashboard live guidance preview launch 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 guidance preview launch controls directly to gameplay and Blueprint callers.
## Why this packet exists
`UHyperTwistCoachDashboardWidget` already displayed:
- the `Start Preview Deck` action label
- the `Start Selected Preview Case` action label
- the enablement posture behind those two preview-launch controls
But that control band still only surfaced through button labels and `SetIsEnabled` state. Callers still had to scrape widget controls to understand whether the dashboard currently has a launchable preview deck, whether a selected preview case can be launched directly, and what live run/timer gating is blocking those actions.
## What changed
- added `FHyperTwistTrainingCoachDashboardGuidancePreviewLaunchActionControlInspectSurface`
- added `GetDisplayedGuidancePreviewLaunchActionControlInspectSurface()`
- retained the exact displayed `Start Preview Deck` and `Start Selected Preview Case` 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 preview-deck derivation 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 `Start Preview Deck` label
- the exact displayed `Start Selected Preview Case` label
- whether preview-deck launch is currently enabled
- whether selected-preview-case launch is currently enabled
- the active preview lane, selected case ordinal, selected case id, surfaced prompt label, and launch gating posture behind those two controls
without scraping widget button text or reopening preview-launch gating logic.
## Validation
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
- passed with `0 Warning(s), 0 Error(s)`
## Next clean slice
Treat the preview-control seam as functionally complete enough and pivot slightly earlier in the same live dashboard consumer lane to expose the dedicated template-launch status/detail inspect pair over the exact displayed template-launch lines already cached in the widget.