From 4cd80aaf503eb742e5fd26241484c868db4d243e Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Wed, 6 May 2026 03:03:18 +0200 Subject: [PATCH] Surface generated-mode runtime lane in panel and session actor --- .../HyperTwistTrainingPanelWidget.cpp | 80 +++++++++++++++++++ .../HyperTwistTrainingSessionActor.cpp | 80 +++++++++++++++++++ .../HyperTwistTrainingPanelWidget.h | 39 +++++++++ .../HyperTwistTrainingSessionActor.h | 39 +++++++++ ...MODE_RUNTIME_CONSUMER_PACKET_2026-05-06.md | 72 +++++++++++++++++ 5 files changed, 310 insertions(+) create mode 100644 docs/arch/HYPERTWIST_THIN_GENERATED_MODE_RUNTIME_CONSUMER_PACKET_2026-05-06.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp index 8f2a6a9..a646d7d 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp @@ -27,6 +27,22 @@ void UHyperTwistTrainingPanelWidget::RefreshTrainingState() { CachedRunState = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunState(this); CachedRunSummary = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunSummary(this); + UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedRuntimeSelectionState( + this, + CachedImportedRuntimeSelectionState + ); + UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedGeneratedModeLaunchConfig( + this, + CachedImportedGeneratedModeLaunchConfig + ); + UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedGeneratedModeLaunchRequest( + this, + CachedImportedGeneratedModeLaunchRequest + ); + UHyperTwistTrainingRuntimeLibrary::TryGetLatestGeneratedModeLaunchRequestForActiveDeck( + this, + CachedLatestGeneratedModeLaunchRequestForActiveDeck + ); CachedMethodDrillRunState = UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillRunState(this); CachedMethodDrillSummary = UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillSummary(this); CachedMethodDrillDiagnosticPacket = @@ -109,9 +125,73 @@ void UHyperTwistTrainingPanelWidget::ClearActiveTrainingRun() { UHyperTwistTrainingRuntimeLibrary::ClearActiveTrainingRun(this); LastStepResult = FHyperTwistTrainingRunStepResult(); + LastGeneratedModeExecutionBlockedReason.Reset(); RefreshTrainingState(); } +FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::ApplyActiveImportedRuntimeSelectorOption( + const FString& SelectorId, + const FString& OptionId +) +{ + LastGeneratedModeExecutionBlockedReason.Reset(); + CachedRunState = UHyperTwistTrainingRuntimeLibrary::ApplyActiveImportedRuntimeSelectorOption( + this, + SelectorId, + OptionId + ); + RefreshTrainingState(); + return CachedRunState; +} + +FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::ApplyActiveImportedGeneratedModeSelectorChoice( + const FString& SelectorId, + const FString& SelectedValue, + const FString& DisplayValue +) +{ + LastGeneratedModeExecutionBlockedReason.Reset(); + CachedRunState = UHyperTwistTrainingRuntimeLibrary::ApplyActiveImportedGeneratedModeSelectorChoice( + this, + SelectorId, + SelectedValue, + DisplayValue + ); + RefreshTrainingState(); + return CachedRunState; +} + +FHyperTwistTrainingImportedGeneratedModeLaunchRequest +UHyperTwistTrainingPanelWidget::CreateActiveImportedGeneratedModeLaunchRequest( + const FString& RequestSource +) +{ + LastGeneratedModeExecutionBlockedReason.Reset(); + CachedImportedGeneratedModeLaunchRequest = + UHyperTwistTrainingRuntimeLibrary::CreateActiveImportedGeneratedModeLaunchRequest( + this, + RequestSource + ); + RefreshTrainingState(); + return CachedImportedGeneratedModeLaunchRequest; +} + +bool UHyperTwistTrainingPanelWidget::TryExecuteActiveImportedGeneratedModeLaunchRequest( + FHyperTwistTrainingRunState& OutRunState, + FString& OutBlockedReason +) +{ + const bool bSucceeded = UHyperTwistTrainingRuntimeLibrary::TryExecuteActiveImportedGeneratedModeLaunchRequest( + this, + OutRunState, + OutBlockedReason + ); + CachedRunState = OutRunState; + LastGeneratedModeExecutionBlockedReason = OutBlockedReason; + RefreshTrainingState(); + return bSucceeded; +} + FHyperTwistTrainingDeck UHyperTwistTrainingPanelWidget::BuildActiveCoachRecommendedDeck(const int32 MaxCases) { CachedCoachRecommendedDeck = UHyperTwistTrainingRuntimeLibrary::BuildActiveCoachRecommendedDeck( diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp index fd9779d..0fd98a2 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp @@ -77,6 +77,7 @@ void AHyperTwistTrainingSessionActor::ClearRun() { UHyperTwistTrainingRuntimeLibrary::ClearActiveTrainingRun(this); LastStepResult = FHyperTwistTrainingRunStepResult(); + LastGeneratedModeExecutionBlockedReason.Reset(); RefreshCachedTrainingState(); } @@ -84,6 +85,22 @@ void AHyperTwistTrainingSessionActor::RefreshCachedTrainingState() { CachedRunState = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunState(this); CachedRunSummary = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunSummary(this); + UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedRuntimeSelectionState( + this, + CachedImportedRuntimeSelectionState + ); + UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedGeneratedModeLaunchConfig( + this, + CachedImportedGeneratedModeLaunchConfig + ); + UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedGeneratedModeLaunchRequest( + this, + CachedImportedGeneratedModeLaunchRequest + ); + UHyperTwistTrainingRuntimeLibrary::TryGetLatestGeneratedModeLaunchRequestForActiveDeck( + this, + CachedLatestGeneratedModeLaunchRequestForActiveDeck + ); CachedCoachSignals = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCoachSignals(this); CachedCoachBrief = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCoachBrief(this); CachedCoachFollowUpBrief = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCoachFollowUpBrief(this); @@ -102,6 +119,69 @@ void AHyperTwistTrainingSessionActor::RefreshCachedTrainingState() UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRepositoryRoundTripVerification(this); } +FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::ApplyActiveImportedRuntimeSelectorOption( + const FString& SelectorId, + const FString& OptionId +) +{ + LastGeneratedModeExecutionBlockedReason.Reset(); + CachedRunState = UHyperTwistTrainingRuntimeLibrary::ApplyActiveImportedRuntimeSelectorOption( + this, + SelectorId, + OptionId + ); + RefreshCachedTrainingState(); + return CachedRunState; +} + +FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::ApplyActiveImportedGeneratedModeSelectorChoice( + const FString& SelectorId, + const FString& SelectedValue, + const FString& DisplayValue +) +{ + LastGeneratedModeExecutionBlockedReason.Reset(); + CachedRunState = UHyperTwistTrainingRuntimeLibrary::ApplyActiveImportedGeneratedModeSelectorChoice( + this, + SelectorId, + SelectedValue, + DisplayValue + ); + RefreshCachedTrainingState(); + return CachedRunState; +} + +FHyperTwistTrainingImportedGeneratedModeLaunchRequest +AHyperTwistTrainingSessionActor::CreateActiveImportedGeneratedModeLaunchRequest( + const FString& RequestSource +) +{ + LastGeneratedModeExecutionBlockedReason.Reset(); + CachedImportedGeneratedModeLaunchRequest = + UHyperTwistTrainingRuntimeLibrary::CreateActiveImportedGeneratedModeLaunchRequest( + this, + RequestSource + ); + RefreshCachedTrainingState(); + return CachedImportedGeneratedModeLaunchRequest; +} + +bool AHyperTwistTrainingSessionActor::TryExecuteActiveImportedGeneratedModeLaunchRequest( + FHyperTwistTrainingRunState& OutRunState, + FString& OutBlockedReason +) +{ + const bool bSucceeded = UHyperTwistTrainingRuntimeLibrary::TryExecuteActiveImportedGeneratedModeLaunchRequest( + this, + OutRunState, + OutBlockedReason + ); + CachedRunState = OutRunState; + LastGeneratedModeExecutionBlockedReason = OutBlockedReason; + RefreshCachedTrainingState(); + return bSucceeded; +} + FHyperTwistTrainingDeck AHyperTwistTrainingSessionActor::BuildCoachRecommendedDeck(const int32 MaxCases) { CachedCoachRecommendedDeck = UHyperTwistTrainingRuntimeLibrary::BuildActiveCoachRecommendedDeck( diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h index 20da1e5..3ac983b 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h @@ -86,6 +86,21 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingDeck CachedCoachFollowUpDeck; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedRuntimeSelectionState CachedImportedRuntimeSelectionState; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchConfig CachedImportedGeneratedModeLaunchConfig; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchRequest CachedImportedGeneratedModeLaunchRequest; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchRequest CachedLatestGeneratedModeLaunchRequestForActiveDeck; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FString LastGeneratedModeExecutionBlockedReason; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training") FHyperTwistTrainingRepositoryRoundTripVerification CachedRepositoryRoundTripVerification; @@ -121,6 +136,30 @@ public: UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training") void ClearActiveTrainingRun(); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingRunState ApplyActiveImportedRuntimeSelectorOption( + const FString& SelectorId, + const FString& OptionId + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingRunState ApplyActiveImportedGeneratedModeSelectorChoice( + const FString& SelectorId, + const FString& SelectedValue, + const FString& DisplayValue + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchRequest CreateActiveImportedGeneratedModeLaunchRequest( + const FString& RequestSource + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + bool TryExecuteActiveImportedGeneratedModeLaunchRequest( + FHyperTwistTrainingRunState& OutRunState, + FString& OutBlockedReason + ); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingDeck BuildActiveCoachRecommendedDeck(int32 MaxCases); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h index 73469a9..8da5def 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h @@ -73,6 +73,21 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingDeck CachedCoachFollowUpDeck; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedRuntimeSelectionState CachedImportedRuntimeSelectionState; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchConfig CachedImportedGeneratedModeLaunchConfig; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchRequest CachedImportedGeneratedModeLaunchRequest; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchRequest CachedLatestGeneratedModeLaunchRequestForActiveDeck; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Imported") + FString LastGeneratedModeExecutionBlockedReason; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training") FHyperTwistTrainingRepositoryRoundTripVerification CachedRepositoryRoundTripVerification; @@ -105,6 +120,30 @@ public: UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training") void RefreshCachedTrainingState(); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingRunState ApplyActiveImportedRuntimeSelectorOption( + const FString& SelectorId, + const FString& OptionId + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingRunState ApplyActiveImportedGeneratedModeSelectorChoice( + const FString& SelectorId, + const FString& SelectedValue, + const FString& DisplayValue + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + FHyperTwistTrainingImportedGeneratedModeLaunchRequest CreateActiveImportedGeneratedModeLaunchRequest( + const FString& RequestSource + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Imported") + bool TryExecuteActiveImportedGeneratedModeLaunchRequest( + FHyperTwistTrainingRunState& OutRunState, + FString& OutBlockedReason + ); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach") FHyperTwistTrainingDeck BuildCoachRecommendedDeck(int32 MaxCases); diff --git a/docs/arch/HYPERTWIST_THIN_GENERATED_MODE_RUNTIME_CONSUMER_PACKET_2026-05-06.md b/docs/arch/HYPERTWIST_THIN_GENERATED_MODE_RUNTIME_CONSUMER_PACKET_2026-05-06.md new file mode 100644 index 0000000..f0c3bab --- /dev/null +++ b/docs/arch/HYPERTWIST_THIN_GENERATED_MODE_RUNTIME_CONSUMER_PACKET_2026-05-06.md @@ -0,0 +1,72 @@ +# HyperTwist thin generated-mode runtime consumer packet + +Created on `2026-05-06` + +Status: + +- first-party HyperTwist packet +- bounded thin runtime-consumer slice + +## Purpose + +This packet defines the next logical thin-consumer step after the generated-mode executor and the restart-doc sync packet. + +The open task is: + +- mirror the stabilized imported generated-mode selector/request/execute lane into the generic runtime consumer surfaces that already wrap coach-run flows + +It is not: + +- a new generated-mode backend +- a dashboard redesign +- a broad blueprint API sweep +- a widening of the bounded imported lane + +## Scope + +Bounded lane: + +- surface the existing generated-mode runtime-library lane through: + - `UHyperTwistTrainingPanelWidget` + - `AHyperTwistTrainingSessionActor` + +Required result: + +- the generic panel widget and session actor cache active imported selection state, active generated-mode launch config/request, and latest generated-mode request for the active deck +- both surfaces expose thin wrappers for: + - applying imported selector options + - applying generated-mode selector choices + - creating the active generated-mode launch request + - executing the active generated-mode launch request + +Out of scope: + +- new product UI +- new execution heuristics +- changes to the owned generated-mode executor itself +- external plugin copies + +## Current owned product truth + +These pieces are already live in first-party code: + +- runtime-library wrappers for generated-mode selector, launch-request, and execute behavior +- dashboard consumer flow for generated-mode execution +- coach-panel state carrying generated-mode readiness / blocked-reason fields + +What was still missing: + +- parity in the generic runtime consumer surfaces that already mirror coach-run entry points + +## Acceptance criteria + +- panel widget and session actor can drive the bounded generated-mode selector/request/execute lane without reaching around them to call the runtime library directly +- full UE build still succeeds + +## Validation checklist + +1. build `UnrealHyperTwist.sln` +2. confirm the new panel/widget methods compile against the existing runtime-library wrappers +3. confirm the new cached generated-mode fields refresh with the rest of runtime state + +That is the packet.