diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 87229e5..f06b7e4 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -1977,6 +1977,89 @@ namespace HyperTwistCoachDashboardWidgetInternal return TEXT("Unknown"); } + FString BuildDisplayedGeneratedLaunchRequestDetail( + const FHyperTwistTrainingCoachPanelState& PanelState + ) + { + return PanelState.bHasLatestGeneratedModeLaunchRequest + ? FString::Printf( + TEXT("Generated request: %s @ %s | mode: %s\nSelectors: %s"), + PanelState.LatestGeneratedModeLaunchRequestId.IsEmpty() + ? TEXT("n/a") + : *PanelState.LatestGeneratedModeLaunchRequestId, + PanelState.LatestGeneratedModeLaunchRequestedAtUtc.IsEmpty() + ? TEXT("n/a") + : *PanelState.LatestGeneratedModeLaunchRequestedAtUtc, + PanelState.LatestGeneratedModeRuntimeModeId.IsEmpty() + ? TEXT("n/a") + : *PanelState.LatestGeneratedModeRuntimeModeId, + PanelState.LatestGeneratedModeSelectorSummaryLine.IsEmpty() + ? TEXT("none") + : *PanelState.LatestGeneratedModeSelectorSummaryLine) + : TEXT("Generated request: none for active deck"); + } + + FString BuildDisplayedGeneratedExecutionDetail( + const FHyperTwistTrainingCoachPanelState& PanelState + ) + { + return PanelState.bHasActiveGeneratedModeExecutionTarget + ? FString::Printf( + TEXT("Generated execution ready: %s | Request refresh on execute: %s | Blocked: %s"), + PanelState.bCanExecuteActiveGeneratedModeLaunchRequest ? TEXT("yes") : TEXT("no"), + PanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest + ? TEXT("yes") + : TEXT("no"), + PanelState.ActiveGeneratedModeExecutionBlockedReason.IsEmpty() + ? TEXT("none") + : *PanelState.ActiveGeneratedModeExecutionBlockedReason) + : TEXT(""); + } + + FString BuildDisplayedRepositoryVerificationDetailLine( + const FHyperTwistTrainingRepositoryRoundTripVerification& Verification, + const FString& VerificationNotePreview, + const FHyperTwistTrainingCoachPanelState& PanelState + ) + { + const FString GeneratedLaunchRequestDetail = + BuildDisplayedGeneratedLaunchRequestDetail(PanelState); + const FString GeneratedExecutionDetail = + BuildDisplayedGeneratedExecutionDetail(PanelState); + const FString GeneratedExecutionSuffix = GeneratedExecutionDetail.IsEmpty() + ? TEXT("") + : FString::Printf(TEXT("\n%s"), *GeneratedExecutionDetail); + return FString::Printf( + TEXT("Path: %s\nRound-trip pass: %s | Save: %s | Load: %s | Count parity: %s | State parity: %s | Integrity parity: %s | Derived parity: %s\nRuns %d/%d | Learners %d/%d | Reviews %d/%d | Plans %d/%d | Queues %d/%d | History %d/%d | Derived users %d | Derived queues %d | Notes: %s\n%s%s"), + Verification.ResolvedPath.IsEmpty() + ? TEXT("not yet verified") + : *Verification.ResolvedPath, + Verification.bDidRoundTripPass ? TEXT("yes") : TEXT("no"), + Verification.bSaveSucceeded ? TEXT("yes") : TEXT("no"), + Verification.bLoadSucceeded ? TEXT("yes") : TEXT("no"), + Verification.bRepositoryCountsMatch ? TEXT("yes") : TEXT("no"), + Verification.bSerializedStateMatch ? TEXT("yes") : TEXT("no"), + Verification.bIntegrityReportMatch ? TEXT("yes") : TEXT("no"), + Verification.bDerivedStateMatch ? TEXT("yes") : TEXT("no"), + Verification.LoadedRunRecordCount, + Verification.ExpectedRunRecordCount, + Verification.LoadedLearnerStateCount, + Verification.ExpectedLearnerStateCount, + Verification.LoadedReviewPlanCount, + Verification.ExpectedReviewPlanCount, + Verification.LoadedCoachActionPlanCount, + Verification.ExpectedCoachActionPlanCount, + Verification.LoadedCoachSessionQueueCount, + Verification.ExpectedCoachSessionQueueCount, + Verification.LoadedCoachSessionQueueHistoryCount, + Verification.ExpectedCoachSessionQueueHistoryCount, + Verification.VerifiedDerivedUserCount, + Verification.VerifiedDerivedQueueCount, + *VerificationNotePreview, + *GeneratedLaunchRequestDetail, + *GeneratedExecutionSuffix); + } + bool IsTightCoachPlanPosture( const EHyperTwistTrainingDeliveryMode SuggestedMode, const EHyperTwistTrainingSelectionPolicy SuggestedSelectionPolicy) @@ -12269,6 +12352,108 @@ UHyperTwistCoachDashboardWidget::GetDisplayedVerificationActionInspectSurface() return Surface; } +FHyperTwistTrainingCoachDashboardRepositoryVerificationStatusInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedRepositoryVerificationStatusInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardRepositoryVerificationStatusInspectSurface Surface; + Surface.Headline = TEXT("Repository verification status"); + + const FString VerificationNotePreview = CachedRepositoryRoundTripVerification.VerificationNotes.Num() > 0 + ? CachedRepositoryRoundTripVerification.VerificationNotes[0] + : TEXT("none"); + Surface.RepositoryPath = CachedRepositoryRoundTripVerification.ResolvedPath.IsEmpty() + ? TEXT("not yet verified") + : CachedRepositoryRoundTripVerification.ResolvedPath; + Surface.LatestNote = VerificationNotePreview; + Surface.GeneratedLaunchRequestDetail = + HyperTwistCoachDashboardWidgetInternal::BuildDisplayedGeneratedLaunchRequestDetail( + CachedCoachPanelState); + Surface.GeneratedExecutionDetail = + HyperTwistCoachDashboardWidgetInternal::BuildDisplayedGeneratedExecutionDetail( + CachedCoachPanelState); + Surface.StatusLine = !DisplayedVerificationStatusLine.IsEmpty() + ? DisplayedVerificationStatusLine + : (CachedCoachPanelState.VerificationStatusLine.IsEmpty() + ? TEXT("Repository verification status: not yet populated.") + : CachedCoachPanelState.VerificationStatusLine); + Surface.DetailLine = !DisplayedVerificationDetailLine.IsEmpty() + ? DisplayedVerificationDetailLine + : HyperTwistCoachDashboardWidgetInternal::BuildDisplayedRepositoryVerificationDetailLine( + CachedRepositoryRoundTripVerification, + VerificationNotePreview, + CachedCoachPanelState); + Surface.bHasResolvedPath = !CachedRepositoryRoundTripVerification.ResolvedPath.IsEmpty(); + Surface.bDidRoundTripPass = CachedRepositoryRoundTripVerification.bDidRoundTripPass; + Surface.bSaveSucceeded = CachedRepositoryRoundTripVerification.bSaveSucceeded; + Surface.bLoadSucceeded = CachedRepositoryRoundTripVerification.bLoadSucceeded; + Surface.bCountsMatched = CachedRepositoryRoundTripVerification.bRepositoryCountsMatch; + Surface.bStateMatched = CachedRepositoryRoundTripVerification.bSerializedStateMatch; + Surface.bIntegrityMatched = CachedRepositoryRoundTripVerification.bIntegrityReportMatch; + Surface.bDerivedMatched = CachedRepositoryRoundTripVerification.bDerivedStateMatch; + Surface.bHasGeneratedLaunchRequest = CachedCoachPanelState.bHasLatestGeneratedModeLaunchRequest; + Surface.bHasGeneratedExecutionTarget = CachedCoachPanelState.bHasActiveGeneratedModeExecutionTarget; + Surface.bCanExecuteGeneratedLaunchRequest = + CachedCoachPanelState.bCanExecuteActiveGeneratedModeLaunchRequest; + Surface.bGeneratedExecutionWillRefreshRequest = + CachedCoachPanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest; + return Surface; +} + +FHyperTwistTrainingCoachDashboardRecognitionStatusInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedRecognitionStatusInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardRecognitionStatusInspectSurface Surface; + Surface.Headline = TEXT("Recognition status"); + + const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid() + && CachedRunState.ActiveDeck.IsStructurallyValid(); + Surface.StatusLine = !DisplayedRecognitionStatusLine.IsEmpty() + ? DisplayedRecognitionStatusLine + : (CachedCoachPanelState.RecognitionStatusLine.IsEmpty() + ? TEXT("Recognition status: not yet populated.") + : CachedCoachPanelState.RecognitionStatusLine); + Surface.DetailLine = !DisplayedRecognitionDetailLine.IsEmpty() + ? DisplayedRecognitionDetailLine + : CachedCoachPanelState.RecognitionDetailLine; + Surface.RunModeLabel = bHasActiveRun + ? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.Mode) + : TEXT("n/a"); + Surface.bHasActiveRun = bHasActiveRun; + Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer; + Surface.bHasRecognitionStatus = !CachedCoachPanelState.RecognitionStatusLine.IsEmpty(); + Surface.bHasRecognitionDetail = !CachedCoachPanelState.RecognitionDetailLine.IsEmpty(); + return Surface; +} + +FHyperTwistTrainingCoachDashboardReviewPolicyStatusInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedReviewPolicyStatusInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardReviewPolicyStatusInspectSurface Surface; + Surface.Headline = TEXT("Review-policy status"); + + const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid() + && CachedRunState.ActiveDeck.IsStructurallyValid(); + const bool bHasRunnableCurrentCase = + bHasActiveRun && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid(); + Surface.StatusLine = !DisplayedReviewPolicyStatusLine.IsEmpty() + ? DisplayedReviewPolicyStatusLine + : (CachedCoachPanelState.ReviewPolicyStatusLine.IsEmpty() + ? TEXT("Review-policy status: not yet populated.") + : CachedCoachPanelState.ReviewPolicyStatusLine); + Surface.DetailLine = !DisplayedReviewPolicyDetailLine.IsEmpty() + ? DisplayedReviewPolicyDetailLine + : CachedCoachPanelState.ReviewPolicyDetailLine; + Surface.RunModeLabel = bHasActiveRun + ? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.Mode) + : TEXT("n/a"); + Surface.bHasActiveRun = bHasActiveRun; + Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer; + Surface.bHasRunnableCurrentCase = bHasRunnableCurrentCase; + Surface.bHasReviewPolicyStatus = !CachedCoachPanelState.ReviewPolicyStatusLine.IsEmpty(); + Surface.bHasReviewPolicyDetail = !CachedCoachPanelState.ReviewPolicyDetailLine.IsEmpty(); + return Surface; +} + FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface UHyperTwistCoachDashboardWidget::GetDisplayedSelectedQueueNavigationInspectSurface() const { @@ -25629,23 +25814,28 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() } if (VerificationStatusTextBlock != nullptr) { - VerificationStatusTextBlock->SetText(FText::FromString(CachedCoachPanelState.VerificationStatusLine)); + DisplayedVerificationStatusLine = CachedCoachPanelState.VerificationStatusLine; + VerificationStatusTextBlock->SetText(FText::FromString(DisplayedVerificationStatusLine)); } if (RecognitionStatusTextBlock != nullptr) { - RecognitionStatusTextBlock->SetText(FText::FromString(CachedCoachPanelState.RecognitionStatusLine)); + DisplayedRecognitionStatusLine = CachedCoachPanelState.RecognitionStatusLine; + RecognitionStatusTextBlock->SetText(FText::FromString(DisplayedRecognitionStatusLine)); } if (RecognitionDetailTextBlock != nullptr) { - RecognitionDetailTextBlock->SetText(FText::FromString(CachedCoachPanelState.RecognitionDetailLine)); + DisplayedRecognitionDetailLine = CachedCoachPanelState.RecognitionDetailLine; + RecognitionDetailTextBlock->SetText(FText::FromString(DisplayedRecognitionDetailLine)); } if (ReviewPolicyStatusTextBlock != nullptr) { - ReviewPolicyStatusTextBlock->SetText(FText::FromString(CachedCoachPanelState.ReviewPolicyStatusLine)); + DisplayedReviewPolicyStatusLine = CachedCoachPanelState.ReviewPolicyStatusLine; + ReviewPolicyStatusTextBlock->SetText(FText::FromString(DisplayedReviewPolicyStatusLine)); } if (ReviewPolicyDetailTextBlock != nullptr) { - ReviewPolicyDetailTextBlock->SetText(FText::FromString(CachedCoachPanelState.ReviewPolicyDetailLine)); + DisplayedReviewPolicyDetailLine = CachedCoachPanelState.ReviewPolicyDetailLine; + ReviewPolicyDetailTextBlock->SetText(FText::FromString(DisplayedReviewPolicyDetailLine)); } if (VerificationHeaderTextBlock != nullptr) { @@ -25653,66 +25843,12 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() } if (VerificationDetailTextBlock != nullptr) { - const FString GeneratedLaunchRequestDetail = CachedCoachPanelState.bHasLatestGeneratedModeLaunchRequest - ? FString::Printf( - TEXT("\nGenerated request: %s @ %s | mode: %s\nSelectors: %s"), - CachedCoachPanelState.LatestGeneratedModeLaunchRequestId.IsEmpty() - ? TEXT("n/a") - : *CachedCoachPanelState.LatestGeneratedModeLaunchRequestId, - CachedCoachPanelState.LatestGeneratedModeLaunchRequestedAtUtc.IsEmpty() - ? TEXT("n/a") - : *CachedCoachPanelState.LatestGeneratedModeLaunchRequestedAtUtc, - CachedCoachPanelState.LatestGeneratedModeRuntimeModeId.IsEmpty() - ? TEXT("n/a") - : *CachedCoachPanelState.LatestGeneratedModeRuntimeModeId, - CachedCoachPanelState.LatestGeneratedModeSelectorSummaryLine.IsEmpty() - ? TEXT("none") - : *CachedCoachPanelState.LatestGeneratedModeSelectorSummaryLine - ) - : TEXT("\nGenerated request: none for active deck"); - const FString GeneratedExecutionDetail = - CachedCoachPanelState.bHasActiveGeneratedModeExecutionTarget - ? FString::Printf( - TEXT("\nGenerated execution ready: %s | Request refresh on execute: %s | Blocked: %s"), - CachedCoachPanelState.bCanExecuteActiveGeneratedModeLaunchRequest ? TEXT("yes") : TEXT("no"), - CachedCoachPanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest - ? TEXT("yes") - : TEXT("no"), - CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason.IsEmpty() - ? TEXT("none") - : *CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason - ) - : TEXT(""); - VerificationDetailTextBlock->SetText(FText::FromString(FString::Printf( - TEXT("Path: %s\nRound-trip pass: %s | Save: %s | Load: %s | Count parity: %s | State parity: %s | Integrity parity: %s | Derived parity: %s\nRuns %d/%d | Learners %d/%d | Reviews %d/%d | Plans %d/%d | Queues %d/%d | History %d/%d | Derived users %d | Derived queues %d | Notes: %s%s%s"), - CachedRepositoryRoundTripVerification.ResolvedPath.IsEmpty() - ? TEXT("not yet verified") - : *CachedRepositoryRoundTripVerification.ResolvedPath, - CachedRepositoryRoundTripVerification.bDidRoundTripPass ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.bSaveSucceeded ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.bLoadSucceeded ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.bRepositoryCountsMatch ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.bSerializedStateMatch ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.bIntegrityReportMatch ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.bDerivedStateMatch ? TEXT("yes") : TEXT("no"), - CachedRepositoryRoundTripVerification.LoadedRunRecordCount, - CachedRepositoryRoundTripVerification.ExpectedRunRecordCount, - CachedRepositoryRoundTripVerification.LoadedLearnerStateCount, - CachedRepositoryRoundTripVerification.ExpectedLearnerStateCount, - CachedRepositoryRoundTripVerification.LoadedReviewPlanCount, - CachedRepositoryRoundTripVerification.ExpectedReviewPlanCount, - CachedRepositoryRoundTripVerification.LoadedCoachActionPlanCount, - CachedRepositoryRoundTripVerification.ExpectedCoachActionPlanCount, - CachedRepositoryRoundTripVerification.LoadedCoachSessionQueueCount, - CachedRepositoryRoundTripVerification.ExpectedCoachSessionQueueCount, - CachedRepositoryRoundTripVerification.LoadedCoachSessionQueueHistoryCount, - CachedRepositoryRoundTripVerification.ExpectedCoachSessionQueueHistoryCount, - CachedRepositoryRoundTripVerification.VerifiedDerivedUserCount, - CachedRepositoryRoundTripVerification.VerifiedDerivedQueueCount, - *VerificationNotePreview, - *GeneratedLaunchRequestDetail, - *GeneratedExecutionDetail - ))); + DisplayedVerificationDetailLine = + HyperTwistCoachDashboardWidgetInternal::BuildDisplayedRepositoryVerificationDetailLine( + CachedRepositoryRoundTripVerification, + VerificationNotePreview, + CachedCoachPanelState); + VerificationDetailTextBlock->SetText(FText::FromString(DisplayedVerificationDetailLine)); } FString PrimaryLabel = CachedCoachPanelState.PrimaryActionLabel; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index 05adaba..80fb3b4 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -887,6 +887,18 @@ public: FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface GetDisplayedVerificationActionInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardRepositoryVerificationStatusInspectSurface + GetDisplayedRepositoryVerificationStatusInspectSurface() const; + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardRecognitionStatusInspectSurface + GetDisplayedRecognitionStatusInspectSurface() const; + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardReviewPolicyStatusInspectSurface + GetDisplayedReviewPolicyStatusInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface GetDisplayedSelectedQueueNavigationInspectSurface() const; @@ -2001,6 +2013,12 @@ private: FString DisplayedFollowUpDeckPreviewLine; FString DisplayedPrimaryActionLabel; FString DisplayedVerificationActionLabel; + FString DisplayedVerificationStatusLine; + FString DisplayedVerificationDetailLine; + FString DisplayedRecognitionStatusLine; + FString DisplayedRecognitionDetailLine; + FString DisplayedReviewPolicyStatusLine; + FString DisplayedReviewPolicyDetailLine; FString DisplayedDeferQueueActionLabel; FString DisplayedPromoteQueueActionLabel; FString DisplayedQueueRecoveryActionLabel; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index 50a24f9..909e2c0 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -11833,6 +11833,156 @@ struct FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface } }; +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardRepositoryVerificationStatusInspectSurface +{ + 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 RepositoryPath; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString LatestNote; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GeneratedLaunchRequestDetail; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GeneratedExecutionDetail; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasResolvedPath = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bDidRoundTripPass = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSaveSucceeded = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bLoadSucceeded = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCountsMatched = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bStateMatched = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bIntegrityMatched = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bDerivedMatched = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasGeneratedLaunchRequest = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasGeneratedExecutionTarget = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCanExecuteGeneratedLaunchRequest = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bGeneratedExecutionWillRefreshRequest = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !DetailLine.IsEmpty() + || bDidRoundTripPass + || bHasGeneratedLaunchRequest; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardRecognitionStatusInspectSurface +{ + 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 RunModeLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasActiveRun = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasLiveAttemptTimer = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasRecognitionStatus = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasRecognitionDetail = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !DetailLine.IsEmpty() + || bHasRecognitionStatus + || bHasRecognitionDetail; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardReviewPolicyStatusInspectSurface +{ + 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 RunModeLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasActiveRun = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasLiveAttemptTimer = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasRunnableCurrentCase = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasReviewPolicyStatus = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasReviewPolicyDetail = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !DetailLine.IsEmpty() + || bHasReviewPolicyStatus + || bHasReviewPolicyDetail; + } +}; + USTRUCT(BlueprintType) struct FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface { diff --git a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md index 7096fd7..68517ed 100644 --- a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md +++ b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md @@ -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 retained-history navigation/control lane and adds the template launch history navigation control inspect surface over already-retained template-backed runs, so gameplay/Blueprint callers can inspect the live prev/next template-launch labels, enablement posture, selected retained launch ordinal, and template/state/analytics/latest-selection context without scraping button text or reopening retained-history derivation - - the retained-history navigation/control lane now appears complete enough to reassess whether to pivot deliberately into the next broader `Phase 4` roadmap lane rather than widening this seam by drift + - the latest landed bounded `Phase 4` packet pivots deliberately into a fresh live dashboard verification/recognition/review-policy status lane and adds displayed repository verification status, displayed recognition status, and displayed review-policy status inspect surfaces over already-derived coach panel and repository verification state, so gameplay/Blueprint callers can inspect the exact displayed verification band, recognition posture, and review-policy lines without scraping widget text or reopening those derivation paths + - the next best clean move is to stay adjacent in that same live dashboard consumer band and expose the main queue-recovery live status/detail inspect pair rather than drifting back into retained-history navigation wrappers or backend continuity - 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 diff --git a/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_VERIFICATION_RECOGNITION_REVIEW_POLICY_STATUS_INSPECT_SURFACE_PACKET_2026-05-10.md b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_VERIFICATION_RECOGNITION_REVIEW_POLICY_STATUS_INSPECT_SURFACE_PACKET_2026-05-10.md new file mode 100644 index 0000000..e6f3cad --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_VERIFICATION_RECOGNITION_REVIEW_POLICY_STATUS_INSPECT_SURFACE_PACKET_2026-05-10.md @@ -0,0 +1,57 @@ +# HyperTwist Phase 4 dashboard live verification, recognition, and review-policy status inspect surface packet + +- bounded Phase `4` dashboard-consumer slice +- date: `2026-05-10` + +## Intent + +Pivot deliberately out of the now-complete retained-history navigation/control seam and expose the live verification / recognition / review-policy dashboard band directly to gameplay and Blueprint callers. + +## Why this packet exists + +`UHyperTwistCoachDashboardWidget` already displayed: + +- the repository verification status line +- the repository verification detail block, including generated-mode request / execution context +- the recognition status and detail lines +- the review-policy status and detail lines + +But that presentation state still only surfaced through widget text blocks. Callers still had to scrape UI text to understand the live verification band, recognition posture, and review-policy posture. + +## What changed + +- added `FHyperTwistTrainingCoachDashboardRepositoryVerificationStatusInspectSurface` +- added `FHyperTwistTrainingCoachDashboardRecognitionStatusInspectSurface` +- added `FHyperTwistTrainingCoachDashboardReviewPolicyStatusInspectSurface` +- added `GetDisplayedRepositoryVerificationStatusInspectSurface()` +- added `GetDisplayedRecognitionStatusInspectSurface()` +- added `GetDisplayedReviewPolicyStatusInspectSurface()` +- retained the exact displayed verification / recognition / review-policy lines inside the widget so the new surfaces report the same live strings the dashboard is already presenting +- factored the repository-verification detail assembly into shared widget-local helpers so the displayed verification detail block and the new inspect surface stay aligned + +## 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 exact displayed repository verification status line +- the exact displayed repository verification detail block, including generated launch-request and generated execution detail +- the exact displayed recognition status/detail lines +- the exact displayed review-policy status/detail lines + +without scraping widget text or reopening those derivation paths. + +## Validation + +- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln` + - passed with `0 Warning(s), 0 Error(s)` + +## Next clean slice + +Stay adjacent in the live dashboard consumer band and expose the main queue-recovery live status/detail inspect pair.