Expose dashboard closure recovery history navigation surface

This commit is contained in:
axiomlogicnexus 2026-05-10 00:55:48 +02:00
parent 8c27560fe5
commit ef342525bd
5 changed files with 207 additions and 4 deletions

View file

@ -7381,6 +7381,84 @@ UHyperTwistCoachDashboardWidget::GetSelectedClosureRecoveryHistoryInspectSurface
return Surface;
}
FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryNavigationInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedClosureRecoveryHistoryNavigationInspectSurface() const
{
FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryNavigationInspectSurface Surface;
Surface.Headline = TEXT("Closure recovery history navigation");
const FHyperTwistCoachDashboardClosureRecoveryEntry* SelectedEntry =
SelectedClosureRecoveryIndex >= 0
&& SelectedClosureRecoveryIndex < ClosureRecoveryHistoryEntries.Num()
? &ClosureRecoveryHistoryEntries[SelectedClosureRecoveryIndex]
: nullptr;
const bool bNavigationEnabled = ClosureRecoveryHistoryEntries.Num() > 1;
Surface.PreviousLabel = !DisplayedPreviousClosureRecoveryNavigationLabel.IsEmpty()
? DisplayedPreviousClosureRecoveryNavigationLabel
: TEXT("Prev Closure");
Surface.NextLabel = !DisplayedNextClosureRecoveryNavigationLabel.IsEmpty()
? DisplayedNextClosureRecoveryNavigationLabel
: TEXT("Next Closure");
Surface.SelectedEntryIndex = SelectedClosureRecoveryIndex;
Surface.HistoryEntryCount = ClosureRecoveryHistoryEntries.Num();
Surface.bHasSelectedEntry =
SelectedEntry != nullptr && SelectedEntry->IsStructurallyValid();
Surface.bSelectedEntryIsLatest =
Surface.bHasSelectedEntry
&& SelectedClosureRecoveryIndex == ClosureRecoveryHistoryEntries.Num() - 1;
Surface.bPreviousEnabled = bNavigationEnabled;
Surface.bNextEnabled = bNavigationEnabled;
if (!Surface.bHasSelectedEntry)
{
Surface.SelectedEntryOrdinal = TEXT("none");
Surface.RecordedAtUtc = TEXT("n/a");
Surface.SelectedLaneLabel = TEXT("none");
Surface.PreferredGuidanceSourceLabel = TEXT("none");
Surface.PreferredGuidanceSourceDescription =
HyperTwistCoachDashboardWidgetInternal::DescribeCoachMemorySourceLabel(TEXT(""));
Surface.StatusLine =
TEXT("Closure history navigation: no retained closure-recovery shifts recorded yet.");
Surface.DetailLine = FString::Printf(
TEXT("%s: %s | %s: %s | selected latest: no"),
*Surface.PreviousLabel,
Surface.bPreviousEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.NextLabel,
Surface.bNextEnabled ? TEXT("enabled") : TEXT("disabled"));
return Surface;
}
Surface.SelectedEntryOrdinal = FString::Printf(
TEXT("%d/%d"),
SelectedClosureRecoveryIndex + 1,
ClosureRecoveryHistoryEntries.Num());
Surface.RecordedAtUtc = SelectedEntry->RecordedAtUtc.IsEmpty()
? TEXT("n/a")
: SelectedEntry->RecordedAtUtc;
Surface.SelectedLaneLabel = HyperTwistCoachDashboardWidgetInternal::DescribeGuidanceLane(
SelectedEntry->PreferredGuidanceLane);
Surface.PreferredGuidanceSourceLabel = SelectedEntry->PreferredGuidanceSourceLabel.IsEmpty()
? TEXT("none")
: SelectedEntry->PreferredGuidanceSourceLabel;
Surface.PreferredGuidanceSourceDescription =
HyperTwistCoachDashboardWidgetInternal::DescribeCoachMemorySourceLabel(
SelectedEntry->PreferredGuidanceSourceLabel);
Surface.StatusLine = FString::Printf(
TEXT("Closure history navigation: selected %s | Lane: %s | Recorded: %s"),
*Surface.SelectedEntryOrdinal,
*Surface.SelectedLaneLabel,
*Surface.RecordedAtUtc);
Surface.DetailLine = FString::Printf(
TEXT("%s: %s | %s: %s | source: %s | selected latest: %s"),
*Surface.PreviousLabel,
Surface.bPreviousEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.NextLabel,
Surface.bNextEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.PreferredGuidanceSourceDescription,
Surface.bSelectedEntryIsLatest ? TEXT("yes") : TEXT("no"));
return Surface;
}
FHyperTwistTrainingCoachDashboardMethodDrillRecoveryOutcomeHistoryInspectSurface
UHyperTwistCoachDashboardWidget::GetSelectedMethodDrillRecoveryOutcomeHistoryInspectSurface() const
{
@ -24615,7 +24693,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (PreviousClosureRecoveryButtonLabel != nullptr)
{
PreviousClosureRecoveryButtonLabel->SetText(FText::FromString(TEXT("Prev Closure")));
DisplayedPreviousClosureRecoveryNavigationLabel = TEXT("Prev Closure");
PreviousClosureRecoveryButtonLabel->SetText(
FText::FromString(DisplayedPreviousClosureRecoveryNavigationLabel));
}
if (PreviousClosureRecoveryButton != nullptr)
{
@ -24623,7 +24703,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (NextClosureRecoveryButtonLabel != nullptr)
{
NextClosureRecoveryButtonLabel->SetText(FText::FromString(TEXT("Next Closure")));
DisplayedNextClosureRecoveryNavigationLabel = TEXT("Next Closure");
NextClosureRecoveryButtonLabel->SetText(
FText::FromString(DisplayedNextClosureRecoveryNavigationLabel));
}
if (NextClosureRecoveryButton != nullptr)
{

View file

@ -739,6 +739,10 @@ public:
FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryInspectSurface
GetSelectedClosureRecoveryHistoryInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryNavigationInspectSurface
GetDisplayedClosureRecoveryHistoryNavigationInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardMethodDrillRecoveryOutcomeHistoryInspectSurface
GetSelectedMethodDrillRecoveryOutcomeHistoryInspectSurface() const;
@ -1990,6 +1994,8 @@ private:
FString DisplayedPreviousQueueNavigationLabel;
FString DisplayedStartSelectedQueueActionLabel;
FString DisplayedNextQueueNavigationLabel;
FString DisplayedPreviousClosureRecoveryNavigationLabel;
FString DisplayedNextClosureRecoveryNavigationLabel;
FString DisplayedPreviousAttemptNavigationLabel;
FString DisplayedNextAttemptNavigationLabel;
EHyperTwistCoachDashboardGuidancePreviewLane ActiveGuidancePreviewLane =

View file

@ -8657,6 +8657,69 @@ struct FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryInspectSurface
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryNavigationInspectSurface
{
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 PreviousLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString NextLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedEntryOrdinal;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecordedAtUtc;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedLaneLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PreferredGuidanceSourceLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PreferredGuidanceSourceDescription;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 SelectedEntryIndex = INDEX_NONE;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 HistoryEntryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelectedEntry = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSelectedEntryIsLatest = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreviousEnabled = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bNextEnabled = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bHasSelectedEntry
|| bPreviousEnabled
|| bNextEnabled;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardMethodDrillRecoveryOutcomeHistoryInspectSurface
{

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 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 latest landed bounded `Phase 4` packet stays on that same live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds the closure-recovery history navigation control inspect surface over already-retained history state, so gameplay/Blueprint callers can inspect the live prev/next closure-history labels, enablement posture, selected retained entry ordinal, and source/latest-selection context without scraping button text or reopening retained-history derivation
- the next clean move is to pivot deliberately into the adjacent retained-history navigation/control lane and expose the queue-suppression history navigation control surface rather than drifting back into backend continuity or widening the now-complete closure-recovery live/history 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 closure-recovery history navigation control 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 closure-recovery history navigation controls directly to gameplay and Blueprint callers.
## Why this packet exists
The dashboard already derived and displayed:
- the previous closure-history button label
- the next closure-history button label
- the enablement posture for both controls
But that control state still only surfaced through button text and button enabled state. Callers still had to inspect widget controls directly to understand whether retained closure-history navigation is available and which retained entry is currently selected.
## What changed
- added `FHyperTwistTrainingCoachDashboardClosureRecoveryHistoryNavigationInspectSurface`
- added `GetDisplayedClosureRecoveryHistoryNavigationInspectSurface()`
- retained the exact displayed previous/next closure-history labels inside the widget so the new inspect surface reports 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 previous/next closure-history labels
- whether closure-history navigation is currently enabled
- the selected retained closure-history ordinal, lane, and recorded time
- the selected retained source description and whether the current selection is the latest retained entry
without scraping button text or reopening retained-history derivation.
## Validation
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
- passed with `0 Warning(s), 0 Error(s)`
## Next clean slice
Pivot into the adjacent retained-history navigation/control lane and expose the queue-suppression history navigation control surface.