From cdc26d5d90ad51d7fee4910a3149be51fef8a168 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Wed, 6 May 2026 16:42:17 +0200 Subject: [PATCH] Prime recognition-assisted run launch through dashboard --- .../HyperTwistCoachDashboardWidget.cpp | 46 ++++++++- .../HyperTwistTrainingSubsystem.cpp | 5 + ...SISTED_LAUNCH_PRIMING_PACKET_2026-05-06.md | 93 +++++++++++++++++++ 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 docs/arch/HYPERTWIST_PHASE4_RECOGNITION_ASSISTED_LAUNCH_PRIMING_PACKET_2026-05-06.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 397be16..510981d 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -3675,6 +3675,19 @@ bool UHyperTwistCoachDashboardWidget::ContinueCurrentRunFlow() } else if (CachedRunState.Session.IsStructurallyValid() && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid()) { + if (CachedRunState.Session.Mode == EHyperTwistTrainingDeliveryMode::RecognitionAssisted) + { + FString RecognitionOpenError; + if (!OpenActiveRecognitionSession(RecognitionOpenError) || !CachedRecognitionSessionState.bSessionOpen) + { + RefreshTrainingState(); + SyncRetainedRunRecap(); + SyncSelectedQueueEntry(); + SyncSelectedAttempt(); + UpdateDashboardPresentation(); + return false; + } + } bSucceeded = StartLiveAttemptTimer(); } else if (CachedCoachPanelState.bCanStartQueuedRun @@ -10245,9 +10258,24 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() const bool bCanExecuteGeneratedModeLaunch = bGeneratedModeLaunchDeck && CachedCoachPanelState.bCanExecuteActiveGeneratedModeLaunchRequest; + const bool bRecognitionAssistedCurrentRun = + CachedRunState.Session.Mode == EHyperTwistTrainingDeliveryMode::RecognitionAssisted; + const bool bRecognitionSessionOpenForCurrentRun = + !bRecognitionAssistedCurrentRun || CachedRecognitionSessionState.bSessionOpen; + const bool bRecognitionServiceReadyForCurrentRun = + !bRecognitionAssistedCurrentRun || CachedRecognitionSessionState.ServiceHealth.bReady; + const FString RecognitionRunBlockedReason = + !CachedRecognitionSessionState.LastError.IsEmpty() + ? CachedRecognitionSessionState.LastError + : (!CachedRecognitionSessionState.ServiceHealth.LastError.IsEmpty() + ? CachedRecognitionSessionState.ServiceHealth.LastError + : TEXT("recognition-session-not-open")); const bool bCanContinueCurrentRun = !bHasLiveAttemptTimer && bHasRunnableCurrentCase && !bLastStepCompletedRun + && (!bRecognitionAssistedCurrentRun + || bRecognitionSessionOpenForCurrentRun + || bRecognitionServiceReadyForCurrentRun) && (!bGeneratedModeLaunchDeck || bCanExecuteGeneratedModeLaunch); const bool bCanLaunchCoachRun = !bHasLiveAttemptTimer && ( @@ -10301,6 +10329,20 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() *CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason ); } + else if (bRecognitionAssistedCurrentRun && !bRecognitionSessionOpenForCurrentRun) + { + TransitionStatusLine = bRecognitionServiceReadyForCurrentRun + ? FString::Printf( + TEXT("Transition: recognition-assisted run is staged on %s. Continue will prime the recognition session and begin the attempt."), + *(CachedRunState.CurrentSelection.TrainingCase.PromptLabel.IsEmpty() + ? ActiveCaseId + : CachedRunState.CurrentSelection.TrainingCase.PromptLabel) + ) + : FString::Printf( + TEXT("Transition: recognition-assisted run is blocked until the recognition sidecar is ready (%s)."), + *RecognitionRunBlockedReason + ); + } else if (bCanContinueCurrentRun) { const FHyperTwistTrainingCase& TransitionCase = CachedRunState.CurrentSelection.TrainingCase; @@ -10360,11 +10402,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() ? (bLiveInspectionPhase ? TEXT("Start Solve") : TEXT("Attempt Active")) : (bGeneratedModeLaunchDeck ? (bCanExecuteGeneratedModeLaunch ? TEXT("Execute Generated Run") : TEXT("Resolve Selectors")) + : (bRecognitionAssistedCurrentRun && !bRecognitionSessionOpenForCurrentRun + ? (bRecognitionServiceReadyForCurrentRun ? TEXT("Prime Recognition") : TEXT("Recognition Blocked")) : (bHasNextCaseFromLastStep ? TEXT("Continue Run") : (bCanContinueCurrentRun ? (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt")) - : TransitionLaunchLabel))); + : TransitionLaunchLabel)))); const bool bHasMethodDrillRun = CachedMethodDrillRunState.IsStructurallyValid(); const bool bHasMethodDrillDiagnosticPacket = CachedMethodDrillDiagnosticPacket.IsStructurallyValid(); const bool bHasMethodDrillFollowUpTemplate = CachedMethodDrillFollowUpTemplate.IsStructurallyValid(); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp index 3fffe85..3c8f0e0 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp @@ -3650,6 +3650,11 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromDe ActiveRunState = UHyperTwistTrainingLibrary::StartTrainingRun(Deck, UserId, SessionId, Mode); ActiveRunState.ImportedGeneratedModeLaunchRequest = ActiveImportedGeneratedModeLaunchRequest; bHasActiveRun = ActiveRunState.IsStructurallyValid(); + if (bHasActiveRun && Mode == EHyperTwistTrainingDeliveryMode::RecognitionAssisted) + { + FString RecognitionOpenError; + OpenActiveRecognitionSession(RecognitionOpenError); + } RefreshSummary(); TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState( TrainingRepositoryState, diff --git a/docs/arch/HYPERTWIST_PHASE4_RECOGNITION_ASSISTED_LAUNCH_PRIMING_PACKET_2026-05-06.md b/docs/arch/HYPERTWIST_PHASE4_RECOGNITION_ASSISTED_LAUNCH_PRIMING_PACKET_2026-05-06.md new file mode 100644 index 0000000..ca547aa --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_RECOGNITION_ASSISTED_LAUNCH_PRIMING_PACKET_2026-05-06.md @@ -0,0 +1,93 @@ +# HyperTwist Phase 4 recognition-assisted launch priming packet + +Created on `2026-05-06` + +Status: + +- first-party HyperTwist packet +- bounded Phase `4` orchestration / recognition follow-on slice + +## Purpose + +This packet advances the first recognition-aware runtime consumer above the already-landed recognition handoff and dashboard inspection slices. + +The open task is: + +- make recognition-assisted run launch behave like a real recognition lane instead of a passive delivery-mode label + +It is not: + +- a broad recognition UI pass +- a transport/protocol rewrite +- a speech or simulation packet +- a general dashboard redesign + +## Scope + +Bounded lane: + +- prime the owned recognition session automatically when a recognition-assisted run is started +- make the dashboard transition surface reflect whether a recognition-assisted run is actually ready to begin +- reuse the existing recognition runtime/session APIs instead of introducing a second orchestration path + +Out of scope: + +- new provider capabilities +- frame-streaming changes +- coach-brief heuristics changes +- broad replay visualization work + +## Why this was the right next packet + +Before this slice: + +- HyperTwist could derive recognition-biased coach guidance +- HyperTwist could start recognition-assisted runs +- HyperTwist could inspect live provider/session/replay-handoff state in the dashboard + +But recognition-assisted launch still had a gap: + +- the run start path did not proactively prime the owned recognition session +- the dashboard transition lane did not distinguish a recognition-assisted run that was ready from one blocked on sidecar readiness + +So the next honest move was: + +- tighten the orchestration seam between recognition-assisted run launch and the owned recognition runtime session + +## What landed + +Primary code changes: + +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp` + - recognition-assisted `StartTrainingRunFromDeck(...)` now attempts to open the owned recognition session immediately after the active run is created +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp` + - the dashboard current-run transition logic now distinguishes: + - recognition-assisted runs whose recognition session is already open + - recognition-assisted runs that can prime the session on continue + - recognition-assisted runs blocked by sidecar readiness failure + - the continue action now primes the recognition session before starting the attempt timer when the active run is recognition-assisted + +## Product effect + +Recognition-assisted launch is now more coherent: + +- starting a recognition-assisted run no longer leaves recognition session setup purely implicit +- dashboard transition messaging now tells the user whether recognition is ready, will be primed on continue, or is blocked +- the same dashboard continue action can now recover the recognition session and start the attempt in one bounded lane when the sidecar is available + +## Acceptance criteria + +- recognition-assisted run launch now attempts to prime the owned recognition session +- dashboard transition copy reflects recognition launch readiness +- continuing a recognition-assisted run primes the recognition session before starting the attempt +- the packet stays within the existing subsystem/runtime/panel/dashboard surfaces +- full product build succeeds + +## Validation checklist + +1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor` +2. confirm ordinary timer/virtual-cube current-run continuation still works +3. confirm generated-mode continuation routing is unchanged +4. confirm recognition-assisted runs now surface clearer launch readiness in the dashboard + +That is the packet.