From 31dcf9057affd227b8618c99d24d8644630bb50e Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Fri, 8 May 2026 22:26:19 +0200 Subject: [PATCH] Expose gameplay selector survivor-phase roster inspect surface --- .../HyperTwistTrainingCoachLibrary.cpp | 271 ++++++++++++++++++ .../HyperTwistTrainingPanelWidget.cpp | 19 ++ .../HyperTwistTrainingSessionActor.cpp | 19 ++ .../HyperTwistTrainingCoachLibrary.h | 10 + .../HyperTwistTrainingPanelWidget.h | 6 + .../HyperTwistTrainingSessionActor.h | 6 + .../HyperTwistTrainingTypes.h | 160 +++++++++++ ...RTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md | 4 +- ...OSTER_INSPECT_SURFACE_PACKET_2026-05-08.md | 33 +++ 9 files changed, 526 insertions(+), 2 deletions(-) create mode 100644 docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_OPTION_OWNED_EXECUTION_SPLIT_PHASE_CURRENT_SELECTION_SURVIVOR_PHASE_ROSTER_INSPECT_SURFACE_PACKET_2026-05-08.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp index 9d6c0bc..a45b668 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp @@ -11005,6 +11005,277 @@ UHyperTwistTrainingCoachLibrary:: return Surface; } +FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface +UHyperTwistTrainingCoachLibrary:: + DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + const FHyperTwistTrainingRunState& RunState, + const FString& SelectorId, + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface, + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface& + OptionLaunchRequestPreviewSurface + ) +{ + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionCanonicalInspectSurface + CanonicalInspectSurface = + DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionCanonicalInspectSurface( + RunState, + SelectorId, + OptionMenuSurface, + OptionLaunchRequestPreviewSurface + ); + + FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface + Surface; + Surface.SelectorId = CanonicalInspectSurface.SelectorId; + Surface.SelectorLabel = CanonicalInspectSurface.SelectorLabel; + Surface.BindingLabel = CanonicalInspectSurface.BindingLabel; + Surface.Headline = + TEXT("Generated Mode Selector Option Owned-Execution Split-Phase Current-Selection Survivor-Phase Roster Inspect"); + Surface.bHasSelector = CanonicalInspectSurface.bHasSelector; + Surface.bHasSelection = CanonicalInspectSurface.bHasSelection; + Surface.bSelectionMatchesAvailableOption = + CanonicalInspectSurface.bSelectionMatchesAvailableOption; + Surface.CurrentSelectionSelectionLine = + CanonicalInspectSurface.CurrentSelectionSelectionLine; + Surface.CurrentSelectionOptionId = + CanonicalInspectSurface.CurrentSelectionOptionId; + Surface.CurrentSelectionOptionLabel = + CanonicalInspectSurface.CurrentSelectionOptionLabel; + Surface.CurrentSelectionOptionValue = + CanonicalInspectSurface.CurrentSelectionOptionValue; + Surface.LaunchRequestPreviewKind = + CanonicalInspectSurface.LaunchRequestPreviewKind; + Surface.bStartsOwnedCaseImmediately = + CanonicalInspectSurface.bStartsOwnedCaseImmediately; + Surface.bHasExactCurrentSelectionSurvivorPhaseRoster = + CanonicalInspectSurface.bHasExactCurrentSelectionCanonicalInspect; + Surface.bRetainsActiveDeckSplitPhaseFusion = + CanonicalInspectSurface.bRetainsActiveDeckSplitPhaseFusion; + Surface.bPreviewBlocked = CanonicalInspectSurface.bPreviewBlocked; + Surface.bCanPreview = CanonicalInspectSurface.bCanPreview; + + if (!SelectorId.IsEmpty()) + { + Surface.Headline = OptionMenuSurface.SelectorLabel.IsEmpty() + ? FString::Printf( + TEXT("Generated Mode Selector Option Owned-Execution Split-Phase Current-Selection Survivor-Phase Roster Inspect: %s"), + *SelectorId + ) + : FString::Printf( + TEXT("Generated Mode Selector Option Owned-Execution Split-Phase Current-Selection Survivor-Phase Roster Inspect: %s"), + *OptionMenuSurface.SelectorLabel + ); + } + + for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewRowSurface& + FusedRow : CanonicalInspectSurface.FusedRows) + { + if (!FusedRow.bSurvivesNormalization || !FusedRow.bHasNormalizedPhaseDetail) + { + continue; + } + + FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectPhaseSurface + PhaseSurface; + PhaseSurface.PhaseId = FusedRow.PhaseId; + PhaseSurface.SourceLabel = FusedRow.SourceLabel; + PhaseSurface.NormalizedLabel = FusedRow.NormalizedLabel; + PhaseSurface.EvaluationOrder = FusedRow.EvaluationOrder; + PhaseSurface.NormalizedOrder = FusedRow.NormalizedOrder; + PhaseSurface.LabelProvenanceLine = FusedRow.LabelProvenanceLine; + PhaseSurface.bSourceLabelWasExplicit = FusedRow.bSourceLabelWasExplicit; + PhaseSurface.bLabelFallsBackToPhaseId = + FusedRow.bLabelFallsBackToPhaseId; + PhaseSurface.bCanPreview = FusedRow.bCanPreview; + PhaseSurface.OrderLine = FusedRow.NormalizedOrder >= 0 + ? FString::Printf( + TEXT("Normalized survivor-phase order on execute: #%d"), + FusedRow.NormalizedOrder + ) + : TEXT("Normalized survivor-phase order on execute: unavailable"); + PhaseSurface.LabelLine = FString::Printf( + TEXT("Normalized survivor-phase label on execute: %s (%s)"), + *FusedRow.NormalizedLabel, + *FusedRow.PhaseId + ); + PhaseSurface.SurvivorRosterLine = FString::Printf( + TEXT("Current-selection survivor-phase roster on execute: evaluation #%d survives as normalized phase #%d with label %s (%s)."), + FusedRow.EvaluationOrder, + FusedRow.NormalizedOrder, + *FusedRow.NormalizedLabel, + *FusedRow.PhaseId + ); + PhaseSurface.DetailLine = FString::Printf( + TEXT("%s | %s | %s"), + *PhaseSurface.OrderLine, + *PhaseSurface.LabelProvenanceLine, + *PhaseSurface.SurvivorRosterLine + ); + Surface.SurvivorPhases.Add(MoveTemp(PhaseSurface)); + } + + Surface.SurvivorPhaseCount = Surface.SurvivorPhases.Num(); + Surface.bHasCurrentSelectionSurvivorPhaseRoster = + Surface.SurvivorPhaseCount > 0; + + for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectPhaseSurface& + PhaseSurface : Surface.SurvivorPhases) + { + if (PhaseSurface.bLabelFallsBackToPhaseId) + { + ++Surface.FallbackLabelPhaseCount; + } + else + { + ++Surface.ExplicitLabelPhaseCount; + } + } + Surface.bHasFallbackLabels = Surface.FallbackLabelPhaseCount > 0; + + Surface.SurvivorPhaseCountLine = Surface.bHasCurrentSelectionSurvivorPhaseRoster + ? FString::Printf( + TEXT("Current-selection surviving normalized phases on execute: %d retained phase%s"), + Surface.SurvivorPhaseCount, + Surface.SurvivorPhaseCount == 1 ? TEXT("") : TEXT("s") + ) + : (CanonicalInspectSurface.bHasCurrentSelectionCanonicalInspectEntry + && !CanonicalInspectSurface.bPreviewBlocked + ? TEXT("Current-selection surviving normalized phases on execute: none") + : TEXT("Current-selection surviving normalized phases on execute: unavailable")); + + if (Surface.SurvivorPhases.Num() > 0) + { + TArray OrderedPhaseLabels; + OrderedPhaseLabels.Reserve(Surface.SurvivorPhases.Num()); + TArray NormalizedLabels; + NormalizedLabels.Reserve(Surface.SurvivorPhases.Num()); + for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectPhaseSurface& + PhaseSurface : Surface.SurvivorPhases) + { + OrderedPhaseLabels.Add( + FString::Printf(TEXT("#%d %s"), PhaseSurface.NormalizedOrder, *PhaseSurface.NormalizedLabel) + ); + NormalizedLabels.Add( + FString::Printf(TEXT("%s (%s)"), *PhaseSurface.NormalizedLabel, *PhaseSurface.PhaseId) + ); + } + + Surface.OrderSummaryLine = FString::Printf( + TEXT("Current-selection normalized survivor-phase order on execute: %s"), + *FString::Join(OrderedPhaseLabels, TEXT(" | ")) + ); + Surface.LabelSummaryLine = FString::Printf( + TEXT("Current-selection normalized survivor-phase labels on execute: %s"), + *FString::Join(NormalizedLabels, TEXT(", ")) + ); + Surface.CurrentSelectionSurvivorRosterLine = FString::Printf( + TEXT("%s | %d explicit labels | %d phase-id fallbacks"), + *Surface.SurvivorPhaseCountLine, + Surface.ExplicitLabelPhaseCount, + Surface.FallbackLabelPhaseCount + ); + } + else if (OptionMenuSurface.bHasUnresolvedSelectionDetail) + { + Surface.OrderSummaryLine = TEXT("Current-selection normalized survivor-phase order on execute: unavailable until the cached selection resolves to an imported option."); + Surface.LabelSummaryLine = TEXT("Current-selection normalized survivor-phase labels on execute: unavailable until the cached selection resolves to an imported option."); + Surface.CurrentSelectionSurvivorRosterLine = + OptionMenuSurface.UnresolvedSelectionLine; + } + else if (CanonicalInspectSurface.bPreviewBlocked) + { + Surface.OrderSummaryLine = + TEXT("Current-selection normalized survivor-phase order on execute: blocked until execute-time fused inspection is available."); + Surface.LabelSummaryLine = + TEXT("Current-selection normalized survivor-phase labels on execute: blocked until execute-time fused inspection is available."); + Surface.CurrentSelectionSurvivorRosterLine = + CanonicalInspectSurface.CurrentSelectionCanonicalInspectLine; + } + else if (CanonicalInspectSurface.bHasCurrentSelectionCanonicalInspectEntry) + { + Surface.OrderSummaryLine = + TEXT("Current-selection normalized survivor-phase order on execute: none"); + Surface.LabelSummaryLine = + TEXT("Current-selection normalized survivor-phase labels on execute: none"); + Surface.CurrentSelectionSurvivorRosterLine = + TEXT("Current-selection survivor-phase roster on execute: none"); + } + else if (OptionMenuSurface.bHasSelection) + { + Surface.OrderSummaryLine = + TEXT("Current-selection normalized survivor-phase order on execute: unavailable"); + Surface.LabelSummaryLine = + TEXT("Current-selection normalized survivor-phase labels on execute: unavailable"); + Surface.CurrentSelectionSurvivorRosterLine = + TEXT("Current selection has no additional owned-execution split-phase survivor-phase roster preview."); + } + else if (OptionMenuSurface.bHasSelector) + { + Surface.OrderSummaryLine = + TEXT("Current-selection normalized survivor-phase order on execute: unresolved"); + Surface.LabelSummaryLine = + TEXT("Current-selection normalized survivor-phase labels on execute: unresolved"); + Surface.CurrentSelectionSurvivorRosterLine = + TEXT("Current selection: unresolved"); + } + else + { + Surface.OrderSummaryLine = + TEXT("Current-selection normalized survivor-phase order on execute: n/a"); + Surface.LabelSummaryLine = + TEXT("Current-selection normalized survivor-phase labels on execute: n/a"); + Surface.CurrentSelectionSurvivorRosterLine = + TEXT("Current selection: n/a"); + } + + if (Surface.bHasCurrentSelectionSurvivorPhaseRoster) + { + Surface.StatusLine = FString::Printf( + TEXT("Generated-mode selector option owned-execution split-phase current-selection survivor-phase roster inspect exposes %d surviving normalized phase%s for the active selection."), + Surface.SurvivorPhaseCount, + Surface.SurvivorPhaseCount == 1 ? TEXT("") : TEXT("s") + ); + } + else if (OptionMenuSurface.bHasSelector && OptionMenuSurface.bHasUnresolvedSelectionDetail) + { + Surface.StatusLine = + TEXT("Generated-mode selector option owned-execution split-phase current-selection survivor-phase roster inspect is active, but the cached selection no longer matches an imported option."); + } + else if (CanonicalInspectSurface.bPreviewBlocked) + { + Surface.StatusLine = + TEXT("Generated-mode selector option owned-execution split-phase current-selection survivor-phase roster inspect resolves the active selection, but execute-time survivor-phase inspection remains blocked."); + } + else if (CanonicalInspectSurface.bHasCurrentSelectionCanonicalInspectEntry) + { + Surface.StatusLine = + TEXT("Generated-mode selector option owned-execution split-phase current-selection survivor-phase roster inspect resolves the active selection, but no normalized surviving phases are currently retained."); + } + else if (OptionMenuSurface.bHasSelector && OptionMenuSurface.bHasSelection) + { + Surface.StatusLine = + TEXT("Generated-mode selector option owned-execution split-phase current-selection survivor-phase roster inspect is active, but the current selection does not expose survivor-phase detail."); + } + else if (OptionMenuSurface.bHasSelector) + { + Surface.StatusLine = + TEXT("Generated-mode selector option owned-execution split-phase current-selection survivor-phase roster inspect is active, but this selector is currently unresolved."); + } + else + { + Surface.StatusLine = CanonicalInspectSurface.StatusLine; + } + + Surface.DetailLine = FString::Printf( + TEXT("%s | %s | %s"), + *Surface.CurrentSelectionSelectionLine, + *Surface.CurrentSelectionSurvivorRosterLine, + *Surface.OrderSummaryLine + ); + + return Surface; +} + FHyperTwistTrainingCoachQueueControlSurface UHyperTwistTrainingCoachLibrary::DeriveCoachQueueControlSurface( const FHyperTwistTrainingCoachSessionQueueState& QueueState, diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp index 6d5d276..00077f1 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp @@ -1176,6 +1176,25 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwne ); } +FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface +UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + const FString& SelectorId +) const +{ + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface = + GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId); + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface + OptionLaunchRequestPreviewSurface = + GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId); + return UHyperTwistTrainingCoachLibrary:: + DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + CachedRunState, + SelectorId, + OptionMenuSurface, + OptionLaunchRequestPreviewSurface + ); +} + FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun( const int32 MaxCases, const FString& StartActionSourceLabel diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp index 27bcf58..1eb40ec 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp @@ -1157,6 +1157,25 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwn ); } +FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface +AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + const FString& SelectorId +) const +{ + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface = + GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId); + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface + OptionLaunchRequestPreviewSurface = + GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId); + return UHyperTwistTrainingCoachLibrary:: + DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + CachedRunState, + SelectorId, + OptionMenuSurface, + OptionLaunchRequestPreviewSurface + ); +} + FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun( const int32 MaxCases ) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h index 5361909..7014c31 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h @@ -937,4 +937,14 @@ public: const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface& OptionLaunchRequestPreviewSurface ); + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach") + static FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface + DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + const FHyperTwistTrainingRunState& RunState, + const FString& SelectorId, + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface, + const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface& + OptionLaunchRequestPreviewSurface + ); }; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h index a43efea..d4ddce5 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h @@ -392,6 +392,12 @@ public: const FString& SelectorId ) const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach") + FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface + GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + const FString& SelectorId + ) const; + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingRunState StartCoachRecommendedRun( int32 MaxCases, diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h index a71ebce..75d4de1 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h @@ -373,6 +373,12 @@ public: const FString& SelectorId ) const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach") + FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface + GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface( + const FString& SelectorId + ) const; + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index 2bd4eda..b6b7b16 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -13480,3 +13480,163 @@ struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPha || bHasCurrentSelectionCanonicalInspectEntry; } }; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectPhaseSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString PhaseId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SourceLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString NormalizedLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 EvaluationOrder = -1; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 NormalizedOrder = -1; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString OrderLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LabelLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LabelProvenanceLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SurvivorRosterLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSourceLabelWasExplicit = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bLabelFallsBackToPhaseId = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCanPreview = false; + + bool IsStructurallyValid() const + { + return !PhaseId.IsEmpty() + || !NormalizedLabel.IsEmpty() + || !OrderLine.IsEmpty() + || !LabelProvenanceLine.IsEmpty() + || bCanPreview; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseCurrentSelectionSurvivorPhaseRosterInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectorId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectorLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString BindingLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CurrentSelectionSelectionLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CurrentSelectionSurvivorRosterLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SurvivorPhaseCountLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString OrderSummaryLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LabelSummaryLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray + SurvivorPhases; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CurrentSelectionOptionId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CurrentSelectionOptionLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CurrentSelectionOptionValue; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind LaunchRequestPreviewKind = + EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 SurvivorPhaseCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 ExplicitLabelPhaseCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 FallbackLabelPhaseCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasSelector = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasSelection = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSelectionMatchesAvailableOption = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasCurrentSelectionSurvivorPhaseRoster = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bStartsOwnedCaseImmediately = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasExactCurrentSelectionSurvivorPhaseRoster = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bRetainsActiveDeckSplitPhaseFusion = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasFallbackLabels = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bPreviewBlocked = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCanPreview = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !SelectorId.IsEmpty() + || !CurrentSelectionSurvivorRosterLine.IsEmpty() + || SurvivorPhases.Num() > 0 + || bHasSelector + || bHasSelection + || bHasCurrentSelectionSurvivorPhaseRoster; + } +}; diff --git a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md index 4fdf770..886b2cd 100644 --- a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md +++ b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md @@ -68,8 +68,8 @@ Current correction call from the source-exposed audit and current execution refr - the imported generated-mode gap is closed; request/config/selection plumbing and the bounded clean-room executor are already landed in first-party code - 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 latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector option owned execution split-phase current-selection canonical inspect surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can render just the actively selected option’s fused split-phase normalization state without scanning the broader option array themselves - - the current next bounded packet is to expose one thin generated-mode selector option owned execution split-phase current-selection survivor-phase roster inspect surface on those same two consumer surfaces so gameplay/Blueprint callers can render only the normalized surviving phases for the active selection without filtering duplicate-pruned and invalid raw rows out of the fused canonical inspect surface themselves + - the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector option owned execution split-phase current-selection survivor-phase roster inspect surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can render only the normalized surviving phases for the active selection without filtering duplicate-pruned and invalid raw rows out of the fused canonical inspect surface themselves + - the current next bounded packet is to expose one thin generated-mode selector option owned execution split-phase current-selection dropped-row audit inspect surface on those same two consumer surfaces so gameplay/Blueprint callers can inspect only duplicate-pruned and invalid raw rows for the active selection without scanning the full fused canonical inspect surface themselves - 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 ## Current execution-reality references diff --git a/docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_OPTION_OWNED_EXECUTION_SPLIT_PHASE_CURRENT_SELECTION_SURVIVOR_PHASE_ROSTER_INSPECT_SURFACE_PACKET_2026-05-08.md b/docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_OPTION_OWNED_EXECUTION_SPLIT_PHASE_CURRENT_SELECTION_SURVIVOR_PHASE_ROSTER_INSPECT_SURFACE_PACKET_2026-05-08.md new file mode 100644 index 0000000..1712eab --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_OPTION_OWNED_EXECUTION_SPLIT_PHASE_CURRENT_SELECTION_SURVIVOR_PHASE_ROSTER_INSPECT_SURFACE_PACKET_2026-05-08.md @@ -0,0 +1,33 @@ +# HyperTwist Phase 4 gameplay generated-mode selector option owned execution split-phase current-selection survivor-phase roster inspect surface packet + +## Goal + +Close the next thin gameplay-facing consumer seam above the current-selection canonical inspect surface by exposing one current-selection survivor-phase roster inspect surface for a chosen selector id. + +## Why this packet exists + +The current-selection canonical inspect surface already exposed the active selection's fused split-phase normalization state, including surviving rows, duplicate-pruned rows, and invalid rows. Gameplay and Blueprint callers that only need the normalized surviving phases still had to filter those fused rows themselves. + +This packet removes that caller-side filtering step. It exposes one thin current-selection survivor-phase roster inspect surface that projects only the normalized surviving phases for the active selection while preserving unresolved-selection and blocked-preview posture from the already-landed canonical inspect surface. + +## What changed + +- add a first-party owned execution split-phase current-selection survivor-phase roster inspect surface in shared training types +- derive that surface in the coach library by projecting the already-landed current-selection canonical inspect surface instead of reimplementing split-phase normalization logic +- expose the current-selection survivor-phase roster inspect surface on both gameplay-facing consumers: + - `UHyperTwistTrainingPanelWidget` + - `AHyperTwistTrainingSessionActor` +- preserve exact survivor-phase order, normalized labels, and label-fallback provenance for the active selection +- preserve unresolved cached-selection and blocked-preview posture when the active selection cannot yet expose a survivor-phase roster + +## Validation + +- full `Development Editor|Win64` solution build for `C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.sln` + +## Result + +Gameplay and Blueprint callers can now render only the active selection's normalized surviving phases from one dedicated survivor-phase roster surface without filtering duplicate-pruned and invalid raw rows out of the broader canonical inspect surface first. + +## Next bounded slice + +Stay on the same gameplay-facing consumer lane and expose one thin generated-mode selector option owned execution split-phase current-selection dropped-row audit inspect surface so callers can inspect only duplicate-pruned and invalid raw rows for the active selection without scanning the full fused canonical inspect surface themselves.