From a8be3a2106f85d47d735b37c68b642060e94bfe9 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Fri, 8 May 2026 01:56:29 +0200 Subject: [PATCH] Expose gameplay generated-mode selector context surface --- .../HyperTwistTrainingCoachLibrary.cpp | 197 ++++++++++++++++++ .../HyperTwistTrainingPanelWidget.cpp | 14 ++ .../HyperTwistTrainingSessionActor.cpp | 14 ++ .../HyperTwistTrainingCoachLibrary.h | 10 + .../HyperTwistTrainingPanelWidget.h | 4 + .../HyperTwistTrainingSessionActor.h | 4 + .../HyperTwistTrainingTypes.h | 76 +++++++ ...RTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md | 4 +- ...ATION_CONTEXT_SURFACE_PACKET_2026-05-08.md | 112 ++++++++++ 9 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_APPLICATION_CONTEXT_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 7e78609..2996f3c 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp @@ -6809,3 +6809,200 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeLaunchExecutionContextS return Surface; } + +FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface +UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorApplicationContextSurface( + const FHyperTwistTrainingDeck& ActiveDeck, + const FHyperTwistTrainingImportedRuntimeSelectionState& ImportedRuntimeSelectionState, + const FHyperTwistTrainingImportedGeneratedModeLaunchConfig& LaunchConfig, + const FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface& LaunchExecutionContextSurface +) +{ + FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface Surface; + Surface.Headline = TEXT("Generated Mode Selectors"); + + const FHyperTwistTrainingImportedRuntimeSurface& RuntimeSurface = ActiveDeck.ImportedRuntimeSurface; + Surface.bHasGeneratedModeSurface = RuntimeSurface.IsStructurallyValid() + && RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase); + Surface.bHasSelectionState = ImportedRuntimeSelectionState.IsStructurallyValid(); + Surface.bHasLaunchConfig = LaunchConfig.IsStructurallyValid(); + Surface.bWillRefreshLaunchRequestOnExecute = + LaunchExecutionContextSurface.bWillRefreshLaunchRequestOnExecute; + Surface.bSelectionStateMatchesSurface = !Surface.bHasGeneratedModeSurface + || !Surface.bHasSelectionState + || ImportedRuntimeSelectionState.SurfaceId == RuntimeSurface.SurfaceId; + + Surface.SurfaceId = Surface.bHasLaunchConfig + ? LaunchConfig.SurfaceId + : (Surface.bHasGeneratedModeSurface + ? RuntimeSurface.SurfaceId + : ImportedRuntimeSelectionState.SurfaceId); + Surface.SurfaceLabel = Surface.bHasLaunchConfig + ? LaunchConfig.SurfaceLabel + : (Surface.bHasGeneratedModeSurface ? RuntimeSurface.SurfaceLabel : FString()); + Surface.SurfaceKind = Surface.bHasGeneratedModeSurface + ? RuntimeSurface.SurfaceKind + : ImportedRuntimeSelectionState.SurfaceKind; + Surface.RuntimeModeId = Surface.bHasLaunchConfig + ? LaunchConfig.RuntimeModeId + : (Surface.bHasGeneratedModeSurface ? RuntimeSurface.RuntimeModeId : FString()); + Surface.GeneratorType = Surface.bHasLaunchConfig + ? LaunchConfig.GeneratorType + : (Surface.bHasGeneratedModeSurface ? RuntimeSurface.GeneratorType : FString()); + + TSet RequiredSelectorIds; + if (Surface.bHasGeneratedModeSurface) + { + for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors) + { + if (Selector.IsStructurallyValid()) + { + RequiredSelectorIds.Add(Selector.SelectorId); + } + } + } + Surface.RequiredSelectorCount = RequiredSelectorIds.Num(); + + TSet SelectedSelectorIds; + if (Surface.bHasSelectionState) + { + for (const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice : + ImportedRuntimeSelectionState.SelectorChoices) + { + if (!Choice.IsStructurallyValid()) + { + continue; + } + if (RequiredSelectorIds.Num() > 0 && !RequiredSelectorIds.Contains(Choice.SelectorId)) + { + continue; + } + SelectedSelectorIds.Add(Choice.SelectorId); + } + } + Surface.SelectedSelectorCount = SelectedSelectorIds.Num(); + Surface.MissingSelectorCount = FMath::Max( + Surface.RequiredSelectorCount - Surface.SelectedSelectorCount, + 0 + ); + Surface.bHasFullSelectorCoverage = Surface.bHasLaunchConfig + || (Surface.bHasSelectionState + && Surface.bSelectionStateMatchesSurface + && Surface.RequiredSelectorCount > 0 + && Surface.MissingSelectorCount == 0); + + const FString SurfaceLabelSummary = Surface.SurfaceLabel.IsEmpty() + ? (Surface.SurfaceId.IsEmpty() ? TEXT("n/a") : Surface.SurfaceId) + : Surface.SurfaceLabel; + const FString SurfaceIdSummary = Surface.SurfaceId.IsEmpty() ? TEXT("n/a") : Surface.SurfaceId; + const FString SurfaceKindSummary = Surface.SurfaceKind.IsEmpty() ? TEXT("n/a") : Surface.SurfaceKind; + const FString RuntimeModeSummary = Surface.RuntimeModeId.IsEmpty() ? TEXT("n/a") : Surface.RuntimeModeId; + const FString GeneratorSummary = Surface.GeneratorType.IsEmpty() ? TEXT("n/a") : Surface.GeneratorType; + const FString CoverageSuffix = Surface.MissingSelectorCount > 0 + ? FString::Printf(TEXT(" | missing: %d"), Surface.MissingSelectorCount) + : FString(); + + if (Surface.RequiredSelectorCount > 0) + { + Surface.CoverageLine = FString::Printf( + TEXT("Coverage: %d/%d selectors selected%s"), + Surface.SelectedSelectorCount, + Surface.RequiredSelectorCount, + *CoverageSuffix + ); + } + else if (Surface.bHasSelectionState) + { + Surface.CoverageLine = FString::Printf( + TEXT("Coverage: %d selector choice%s cached"), + Surface.SelectedSelectorCount, + Surface.SelectedSelectorCount == 1 ? TEXT("") : TEXT("s") + ); + } + else + { + Surface.CoverageLine = TEXT("Coverage: no generated-mode selector choices are cached"); + } + if (!Surface.bSelectionStateMatchesSurface && Surface.bHasGeneratedModeSurface && Surface.bHasSelectionState) + { + Surface.CoverageLine += TEXT(" | selection state is bound to a different surface"); + } + + Surface.IdentityLine = FString::Printf( + TEXT("Identity: %s | kind: %s | mode: %s | generator: %s"), + *SurfaceLabelSummary, + *SurfaceKindSummary, + *RuntimeModeSummary, + *GeneratorSummary + ); + + if (LaunchExecutionContextSurface.bHasExecutionTarget) + { + Surface.RefreshLine = Surface.bWillRefreshLaunchRequestOnExecute + ? TEXT("Refresh posture: execute will rebuild the stored request from the current selector set.") + : TEXT("Refresh posture: execute can use the current stored request without rebuilding it."); + } + else if (Surface.bHasLaunchConfig || Surface.bHasGeneratedModeSurface) + { + Surface.RefreshLine = + TEXT("Refresh posture: no generated-mode execution target is currently staged."); + } + else + { + Surface.RefreshLine = + TEXT("Refresh posture: selector application must stage a generated-mode target first."); + } + + if (Surface.bHasLaunchConfig) + { + Surface.StatusLine = Surface.bWillRefreshLaunchRequestOnExecute + ? TEXT("Generated-mode selector application is complete; execute will refresh the stored request from the current selector set.") + : TEXT("Generated-mode selector application is complete for the active generated-mode surface."); + } + else if (Surface.bHasGeneratedModeSurface && Surface.bHasSelectionState && !Surface.bSelectionStateMatchesSurface) + { + Surface.StatusLine = + TEXT("Generated-mode selector application is cached against a different surface than the active generated-mode deck."); + } + else if (Surface.bHasGeneratedModeSurface && Surface.RequiredSelectorCount > 0 && Surface.MissingSelectorCount == 0) + { + Surface.StatusLine = + TEXT("Generated-mode selector application has full selector coverage, but launch execution is not yet staged."); + } + else if (Surface.bHasGeneratedModeSurface && Surface.RequiredSelectorCount > 0 && Surface.SelectedSelectorCount > 0) + { + Surface.StatusLine = FString::Printf( + TEXT("Generated-mode selector application is in progress; %d selector%s still need selection."), + Surface.MissingSelectorCount, + Surface.MissingSelectorCount == 1 ? TEXT("") : TEXT("s") + ); + } + else if (Surface.bHasGeneratedModeSurface) + { + Surface.StatusLine = + TEXT("Generated-mode selector application has not started for the active generated-mode surface."); + } + else if (Surface.bHasSelectionState) + { + Surface.StatusLine = + TEXT("Generated-mode selector application is cached, but no active generated-mode surface is currently staged."); + } + else + { + Surface.StatusLine = + TEXT("Generated-mode selector application is not currently cached."); + } + + Surface.DetailLine = FString::Printf( + TEXT("Surface: %s (%s) | Runtime: %s | Generator: %s | Launch posture: %s"), + *SurfaceLabelSummary, + *SurfaceIdSummary, + *RuntimeModeSummary, + *GeneratorSummary, + LaunchExecutionContextSurface.StatusLine.IsEmpty() + ? TEXT("n/a") + : *LaunchExecutionContextSurface.StatusLine + ); + + return Surface; +} diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp index b39c683..9c04a6b 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp @@ -677,6 +677,20 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeLaunchExecutionCon ); } +FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface +UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorApplicationContextSurface() const +{ + const FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface + LaunchExecutionContextSurface = + GetDisplayedCoachGeneratedModeLaunchExecutionContextSurface(); + return UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorApplicationContextSurface( + CachedRunState.ActiveDeck, + CachedImportedRuntimeSelectionState, + CachedImportedGeneratedModeLaunchConfig, + LaunchExecutionContextSurface + ); +} + 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 b8096b8..99f04cd 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp @@ -658,6 +658,20 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeLaunchExecutionCo ); } +FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface +AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorApplicationContextSurface() const +{ + const FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface + LaunchExecutionContextSurface = + GetDisplayedCoachGeneratedModeLaunchExecutionContextSurface(); + return UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorApplicationContextSurface( + CachedRunState.ActiveDeck, + CachedImportedRuntimeSelectionState, + CachedImportedGeneratedModeLaunchConfig, + LaunchExecutionContextSurface + ); +} + 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 19b038b..32d8bf8 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h @@ -668,4 +668,14 @@ public: const FHyperTwistTrainingCoachVerificationRecognitionReviewContextSurface& VerificationRecognitionReviewContextSurface ); + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach") + static FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface + DeriveCoachGeneratedModeSelectorApplicationContextSurface( + const FHyperTwistTrainingDeck& ActiveDeck, + const FHyperTwistTrainingImportedRuntimeSelectionState& ImportedRuntimeSelectionState, + const FHyperTwistTrainingImportedGeneratedModeLaunchConfig& LaunchConfig, + const FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface& + LaunchExecutionContextSurface + ); }; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h index dcda8ca..060bf65 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h @@ -248,6 +248,10 @@ public: FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface GetDisplayedCoachGeneratedModeLaunchExecutionContextSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach") + FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface + GetDisplayedCoachGeneratedModeSelectorApplicationContextSurface() 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 dcef09a..3aad2bc 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h @@ -229,6 +229,10 @@ public: FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface GetDisplayedCoachGeneratedModeLaunchExecutionContextSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach") + FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface + GetDisplayedCoachGeneratedModeSelectorApplicationContextSurface() 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 e6ff375..9c1ab90 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -8387,3 +8387,79 @@ struct FHyperTwistTrainingCoachGeneratedModeLaunchExecutionContextSurface || bHasBlockedExecution; } }; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CoverageLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString IdentityLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString RefreshLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SurfaceId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SurfaceLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SurfaceKind; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString RuntimeModeId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GeneratorType; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 SelectedSelectorCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 RequiredSelectorCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 MissingSelectorCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasGeneratedModeSurface = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasSelectionState = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasLaunchConfig = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSelectionStateMatchesSurface = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasFullSelectorCoverage = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bWillRefreshLaunchRequestOnExecute = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !CoverageLine.IsEmpty() + || !IdentityLine.IsEmpty() + || bHasGeneratedModeSurface + || bHasSelectionState + || bHasLaunchConfig; + } +}; diff --git a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md index 5df348a..88cd55d 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 launch-request / execution context surface over the already-cached generated-mode request / execution panel state, so gameplay/Blueprint callers can render latest generated-mode request, runtime mode, selector summary, execution readiness, and blocked-reason context without reading raw request/execution fields directly - - the current next bounded packet is to expose one thin generated-mode selector/application context surface on those same two consumer surfaces so gameplay/Blueprint callers can render active selector-state coverage, generator/runtime identity, and request-refresh implications without reading raw imported selection/config payloads directly + - the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector/application context surface over the already-cached imported selection and launch-config state, so gameplay/Blueprint callers can render active selector-state coverage, generator/runtime identity, and request-refresh implications without reading raw imported selection/config payloads directly + - the current next bounded packet is to expose one thin generated-mode selector roster / option-availability surface on those same two consumer surfaces so gameplay/Blueprint callers can render active selector labels, bindings, and unresolved option availability without reading raw imported runtime selector arrays or option payloads directly - 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_APPLICATION_CONTEXT_SURFACE_PACKET_2026-05-08.md b/docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_APPLICATION_CONTEXT_SURFACE_PACKET_2026-05-08.md new file mode 100644 index 0000000..2f8137d --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_GAMEPLAY_GENERATED_MODE_SELECTOR_APPLICATION_CONTEXT_SURFACE_PACKET_2026-05-08.md @@ -0,0 +1,112 @@ +# HyperTwist Phase 4 gameplay generated-mode selector / application context surface packet + +Created on `2026-05-08` + +Status: + +- first-party HyperTwist packet +- bounded Phase `4` gameplay-facing consumer slice + +## Purpose + +This packet closes the next thin gameplay-facing consumer seam above the panel-widget and session-actor generated-mode helpers by exposing one pure selector / application context surface over the already-cached imported selection state and generated-mode launch-config state. + +The open tasks were: + +- stop forcing gameplay / Blueprint callers to read raw imported selection-state payloads and launch-config payloads just to render selector coverage, generator/runtime identity, and request-refresh implications +- expose one thin first-party context surface that summarizes active selector coverage, generated-mode surface identity, runtime mode, generator type, and refresh-on-execute posture +- keep that surface derived from already-cached gameplay consumer state instead of widening into backend selector application or execution logic + +It is not: + +- a new selector-application behavior packet +- a generated-mode execution packet +- a selector-catalog UI composition pass +- a broader gameplay HUD packet + +## Scope + +Bounded lane: + +- add a first-party generated-mode selector / application context surface in shared training types +- add a coach-library helper that derives the surface from the active deck imported runtime surface, cached imported selection state, cached generated-mode launch config, and the already-landed launch / execution context surface +- expose that derived context surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor` +- keep the derivation presentation-only and rooted in already-cached gameplay consumer state + +Out of scope: + +- changing selector-application persistence behavior +- changing generated-mode launch-config derivation rules +- changing generated-mode execution behavior +- importing dashboard-only generated-mode inspection into gameplay consumers + +## Why this was the right next packet + +Before this slice: + +- gameplay-facing panel/session consumers already exposed a truthful generated-mode launch / execution context surface + +But one thin consumer seam was still open: + +- callers could explain current generated-mode request and execution posture +- but they still had to read raw imported selection/config payloads to explain whether selector application was complete, what runtime/generator identity those selections targeted, and whether execute would rebuild the stored request + +That meant: + +- execution posture was thin and reusable +- but selector-application context still leaked raw imported payloads into callers + +So the next bounded move was: + +- keep the already-landed launch / execution context surface unchanged +- and expose one narrow selector / application context surface above the cached imported selection/config state + +## What landed + +Primary code changes: + +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h` + - added `FHyperTwistTrainingCoachGeneratedModeSelectorApplicationContextSurface` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp` + - added `DeriveCoachGeneratedModeSelectorApplicationContextSurface(...)` + - context is derived from the active imported runtime surface, cached imported selection state, cached generated-mode launch config, and the already-landed launch / execution context surface +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp` + - added `GetDisplayedCoachGeneratedModeSelectorApplicationContextSurface()` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp` + - added `GetDisplayedCoachGeneratedModeSelectorApplicationContextSurface()` + +## Product effect + +The gameplay-facing generated-mode consumer layer is now more complete: + +- gameplay / Blueprint callers can read one pure surface to render selector coverage, missing-selector count, generated-mode surface identity, runtime mode, generator type, and request-refresh implications +- callers no longer need to inspect raw imported selection-state or generated-mode launch-config payloads directly +- the surface stays aligned with the already-landed generated-mode launch / execution context surface without widening backend behavior + +## Acceptance criteria + +- shared training types expose a narrow generated-mode selector / application context surface +- coach-library derivation consumes already-cached gameplay consumer state rather than adding new runtime fetches +- panel-widget callers can fetch the displayed selector / application context surface directly +- session-actor callers can fetch the displayed selector / application context surface directly +- full product build succeeds + +## Validation checklist + +1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor` +2. confirm the new selector / application context surface compiles in shared types and coach library +3. confirm panel-widget getters compile and return the derived context surface +4. confirm session-actor getters compile and return the derived context surface +5. confirm no backend selector-application or generated-mode execution behavior was pulled into the packet + +## Validation result + +- full `Development Editor|Win64` build succeeded on `2026-05-08` +- build completed with `0` warnings and `0` errors + +## Next bounded follow-on slice + +- stay on the same gameplay-facing consumer lane and expose one thin generated-mode selector roster / option-availability surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`, so gameplay callers can render active selector labels, bindings, and unresolved option availability without reading raw imported runtime selector arrays or option payloads directly