From 18e1e065fc96f2b831a2f13ec69f8040a7793ff7 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Sat, 9 May 2026 23:08:38 +0200 Subject: [PATCH] Expose dashboard queue overview and selected entry inspect surfaces --- .../HyperTwistCoachDashboardWidget.cpp | 210 +++++++++++++++++- .../HyperTwistCoachDashboardWidget.h | 17 ++ .../HyperTwistTrainingTypes.h | 195 ++++++++++++++++ ...RTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md | 4 +- ...ETAIL_INSPECT_SURFACE_PACKET_2026-05-09.md | 56 +++++ 5 files changed, 469 insertions(+), 13 deletions(-) create mode 100644 docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_QUEUE_COUNTS_STATUS_SELECTED_QUEUE_SUMMARY_ENTRY_DETAIL_INSPECT_SURFACE_PACKET_2026-05-09.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 583ec08..39bdaeb 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -11548,6 +11548,187 @@ UHyperTwistCoachDashboardWidget::GetDisplayedStartSelectedQueueActionInspectSurf return Surface; } +FHyperTwistTrainingCoachDashboardQueueCountsStatusInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedQueueCountsStatusInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardQueueCountsStatusInspectSurface Surface; + Surface.Headline = TEXT("Queue counts / status"); + + Surface.QueueId = CachedCoachSessionQueueState.QueueId.IsEmpty() + ? TEXT("n/a") + : CachedCoachSessionQueueState.QueueId; + Surface.ActiveQueueEntryId = CachedCoachPanelState.ActiveQueueEntryId.IsEmpty() + ? TEXT("none") + : CachedCoachPanelState.ActiveQueueEntryId; + Surface.NextQueueSourceLabel = CachedCoachPanelState.NextQueueSourceLabel.IsEmpty() + ? TEXT("n/a") + : CachedCoachPanelState.NextQueueSourceLabel; + Surface.SignalCount = CachedCoachPanelState.SignalCount; + Surface.TotalEntryCount = CachedCoachSessionQueueState.TotalEntryCount; + Surface.PendingEntryCount = CachedCoachSessionQueueState.PendingEntryCount; + Surface.ReadyEntryCount = CachedCoachSessionQueueState.ReadyEntryCount; + Surface.DeferredEntryCount = CachedCoachSessionQueueState.DeferredEntryCount; + Surface.InProgressEntryCount = CachedCoachSessionQueueState.InProgressEntryCount; + Surface.CompletedEntryCount = CachedCoachSessionQueueState.CompletedEntryCount; + Surface.QueuedEventCount = CachedCoachQueueExecutionSummary.QueuedEventCount; + Surface.StartedEventCount = CachedCoachQueueExecutionSummary.StartedEventCount; + Surface.CompletedEventCount = CachedCoachQueueExecutionSummary.CompletedEventCount; + Surface.DeferredEventCount = CachedCoachQueueExecutionSummary.DeferredEventCount; + Surface.PromotedEventCount = CachedCoachQueueExecutionSummary.PromotedEventCount; + Surface.ManualRescheduleEventCount = CachedCoachQueueExecutionSummary.ManualRescheduleEventCount; + Surface.bHasOutstandingDeferredWork = CachedCoachQueueExecutionSummary.bHasOutstandingDeferredWork; + Surface.bHasCompletionGap = CachedCoachQueueExecutionSummary.bHasCompletionGap; + Surface.bHasArchiveAwareFriction = CachedCoachQueueExecutionSummary.bHasArchiveAwareFriction; + Surface.bHasBlockedFollowUpFriction = CachedCoachQueueExecutionSummary.bHasBlockedFollowUpFriction; + Surface.StatusLine = !DisplayedQueueStatusLine.IsEmpty() + ? DisplayedQueueStatusLine + : CachedCoachPanelState.QueueStatusLine; + Surface.CountsLine = !DisplayedQueueCountsLine.IsEmpty() + ? DisplayedQueueCountsLine + : FString::Printf( + TEXT("Signals: %d | Ready: %d | Deferred: %d | In-progress: %d | Completed: %d"), + Surface.SignalCount, + Surface.ReadyEntryCount, + Surface.DeferredEntryCount, + Surface.InProgressEntryCount, + Surface.CompletedEntryCount); + Surface.ExecutionLine = !DisplayedQueueExecutionLine.IsEmpty() + ? DisplayedQueueExecutionLine + : FString::Printf( + TEXT("Execution: queued %d | started %d | completed %d | deferred %d | promoted %d | manual reschedules %d | outstanding deferred: %s | completion gap: %s | archive-aware friction: %s | blocked follow-up friction: %s"), + Surface.QueuedEventCount, + Surface.StartedEventCount, + Surface.CompletedEventCount, + Surface.DeferredEventCount, + Surface.PromotedEventCount, + Surface.ManualRescheduleEventCount, + Surface.bHasOutstandingDeferredWork ? TEXT("yes") : TEXT("no"), + Surface.bHasCompletionGap ? TEXT("yes") : TEXT("no"), + Surface.bHasArchiveAwareFriction ? TEXT("yes") : TEXT("no"), + Surface.bHasBlockedFollowUpFriction ? TEXT("yes") : TEXT("no")); + return Surface; +} + +FHyperTwistTrainingCoachDashboardSelectedQueueSummaryInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedSelectedQueueSummaryInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardSelectedQueueSummaryInspectSurface Surface; + Surface.Headline = TEXT("Selected queue summary"); + + const FHyperTwistTrainingCoachSessionQueueStateEntry* SelectedEntry = FindSelectedQueueEntry(); + Surface.SelectedQueueEntryId = + SelectedEntry != nullptr && !SelectedEntry->EntryId.IsEmpty() + ? SelectedEntry->EntryId + : TEXT("none"); + Surface.SelectedQueueSourceLabel = + SelectedEntry != nullptr && !SelectedEntry->SourceLabel.IsEmpty() + ? SelectedEntry->SourceLabel + : TEXT("n/a"); + Surface.SelectedQueueStateLabel = + SelectedEntry != nullptr + ? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(SelectedEntry->EntryState) + : TEXT("n/a"); + Surface.SelectedQueuePriorityLabel = + SelectedEntry != nullptr && !SelectedEntry->PriorityLabel.IsEmpty() + ? SelectedEntry->PriorityLabel + : TEXT("n/a"); + Surface.SelectedQueueOrdinal = + SelectedEntry != nullptr + ? FString::Printf( + TEXT("%d/%d"), + SelectedQueueEntryIndex + 1, + CachedCoachSessionQueueState.Entries.Num()) + : TEXT("none"); + Surface.SelectedQueuePriorityScore = + SelectedEntry != nullptr ? SelectedEntry->PriorityScore : 0.0f; + Surface.SelectedQueueEntryIndex = SelectedQueueEntryIndex; + Surface.TotalQueueEntries = CachedCoachSessionQueueState.Entries.Num(); + Surface.bHasSelectedQueueEntry = SelectedEntry != nullptr; + Surface.bSelectedEntryMatchesActiveQueue = + SelectedEntry != nullptr + && SelectedEntry->EntryId == CachedCoachPanelState.ActiveQueueEntryId; + Surface.StatusLine = !DisplayedSelectedQueueSummaryLine.IsEmpty() + ? DisplayedSelectedQueueSummaryLine + : (SelectedEntry != nullptr + ? FString::Printf( + TEXT("Selected queue item %d/%d | Source: %s | State: %s | Priority: %s (%.1f)"), + SelectedQueueEntryIndex + 1, + CachedCoachSessionQueueState.Entries.Num(), + *Surface.SelectedQueueSourceLabel, + *Surface.SelectedQueueStateLabel, + *Surface.SelectedQueuePriorityLabel, + Surface.SelectedQueuePriorityScore) + : TEXT("Selected queue item: none")); + return Surface; +} + +FHyperTwistTrainingCoachDashboardSelectedQueueEntryDetailInspectSurface +UHyperTwistCoachDashboardWidget::GetDisplayedSelectedQueueEntryDetailInspectSurface() const +{ + FHyperTwistTrainingCoachDashboardSelectedQueueEntryDetailInspectSurface Surface; + Surface.Headline = TEXT("Selected queue-entry detail"); + + const FHyperTwistTrainingCoachSessionQueueStateEntry* SelectedEntry = FindSelectedQueueEntry(); + Surface.SelectedQueueEntryId = + SelectedEntry != nullptr && !SelectedEntry->EntryId.IsEmpty() + ? SelectedEntry->EntryId + : TEXT("none"); + Surface.EntryHeadline = + SelectedEntry != nullptr && !SelectedEntry->Headline.IsEmpty() + ? SelectedEntry->Headline + : TEXT("n/a"); + Surface.FocusDeckId = + SelectedEntry != nullptr && !SelectedEntry->FocusDeckId.IsEmpty() + ? SelectedEntry->FocusDeckId + : TEXT("n/a"); + Surface.FocusMethodSegmentId = + SelectedEntry != nullptr && !SelectedEntry->FocusMethodSegmentId.IsEmpty() + ? SelectedEntry->FocusMethodSegmentId + : TEXT("n/a"); + Surface.SuggestedModeLabel = + SelectedEntry != nullptr + ? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(SelectedEntry->SuggestedMode) + : TEXT("n/a"); + Surface.SuggestedSelectionPolicyLabel = + SelectedEntry != nullptr + ? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName( + SelectedEntry->SuggestedSelectionPolicy) + : TEXT("n/a"); + Surface.DeferredUntilUtc = + SelectedEntry != nullptr && !SelectedEntry->DeferredUntilUtc.IsEmpty() + ? SelectedEntry->DeferredUntilUtc + : TEXT("n/a"); + Surface.DeferralReasonLabel = + SelectedEntry != nullptr && !SelectedEntry->DeferralReasonLabel.IsEmpty() + ? SelectedEntry->DeferralReasonLabel + : TEXT("n/a"); + Surface.FocusCaseCount = SelectedEntry != nullptr ? SelectedEntry->FocusCaseIds.Num() : 0; + Surface.bHasSelectedQueueEntry = SelectedEntry != nullptr; + Surface.bRequiresFollowUp = SelectedEntry != nullptr && SelectedEntry->bRequiresFollowUp; + Surface.bRequiresArchiveRetentionTuning = + SelectedEntry != nullptr && SelectedEntry->bRequiresArchiveRetentionTuning; + Surface.bPinned = SelectedEntry != nullptr && SelectedEntry->bPinned; + Surface.bCanStartImmediately = SelectedEntry != nullptr && SelectedEntry->bCanStartImmediately; + Surface.DetailLine = !DisplayedSelectedQueueEntryDetailLine.IsEmpty() + ? DisplayedSelectedQueueEntryDetailLine + : (SelectedEntry != nullptr + ? FString::Printf( + TEXT("Headline: %s | Deck: %s | Method: %s | Cases: %d | Mode: %s | Policy: %s | Deferred until: %s | Reason: %s | Follow-up: %s | Archive tune: %s | Pinned: %s"), + *Surface.EntryHeadline, + *Surface.FocusDeckId, + *Surface.FocusMethodSegmentId, + Surface.FocusCaseCount, + *Surface.SuggestedModeLabel, + *Surface.SuggestedSelectionPolicyLabel, + *Surface.DeferredUntilUtc, + *Surface.DeferralReasonLabel, + Surface.bRequiresFollowUp ? TEXT("yes") : TEXT("no"), + Surface.bRequiresArchiveRetentionTuning ? TEXT("yes") : TEXT("no"), + Surface.bPinned ? TEXT("yes") : TEXT("no")) + : TEXT("Queue entry detail: no queue entry selected")); + return Surface; +} + FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface UHyperTwistCoachDashboardWidget::GetDisplayedLastAttemptReviewSummaryInspectSurface() const { @@ -23860,13 +24041,14 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() } if (QueueStatusTextBlock != nullptr) { - QueueStatusTextBlock->SetText(FText::FromString(CachedCoachPanelState.QueueStatusLine)); + DisplayedQueueStatusLine = CachedCoachPanelState.QueueStatusLine; + QueueStatusTextBlock->SetText(FText::FromString(DisplayedQueueStatusLine)); } if (QueueSelectionTextBlock != nullptr) { if (const FHyperTwistTrainingCoachSessionQueueStateEntry* SelectedEntry = FindSelectedQueueEntry()) { - QueueSelectionTextBlock->SetText(FText::FromString(FString::Printf( + DisplayedSelectedQueueSummaryLine = FString::Printf( TEXT("Selected queue item %d/%d | Source: %s | State: %s | Priority: %s (%.1f)"), SelectedQueueEntryIndex + 1, CachedCoachSessionQueueState.Entries.Num(), @@ -23874,11 +24056,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() *HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(SelectedEntry->EntryState), SelectedEntry->PriorityLabel.IsEmpty() ? TEXT("n/a") : *SelectedEntry->PriorityLabel, SelectedEntry->PriorityScore - ))); + ); + QueueSelectionTextBlock->SetText(FText::FromString(DisplayedSelectedQueueSummaryLine)); } else { - QueueSelectionTextBlock->SetText(FText::FromString(TEXT("Selected queue item: none"))); + DisplayedSelectedQueueSummaryLine = TEXT("Selected queue item: none"); + QueueSelectionTextBlock->SetText(FText::FromString(DisplayedSelectedQueueSummaryLine)); } } if (QueueEntryDetailTextBlock != nullptr) @@ -23891,7 +24075,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() const FString DeferralReason = SelectedEntry->DeferralReasonLabel.IsEmpty() ? TEXT("n/a") : SelectedEntry->DeferralReasonLabel; - QueueEntryDetailTextBlock->SetText(FText::FromString(FString::Printf( + DisplayedSelectedQueueEntryDetailLine = FString::Printf( TEXT("Headline: %s | Deck: %s | Method: %s | Cases: %d | Mode: %s | Policy: %s | Deferred until: %s | Reason: %s | Follow-up: %s | Archive tune: %s | Pinned: %s"), *SelectedEntry->Headline, SelectedEntry->FocusDeckId.IsEmpty() ? TEXT("n/a") : *SelectedEntry->FocusDeckId, @@ -23904,27 +24088,30 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() SelectedEntry->bRequiresFollowUp ? TEXT("yes") : TEXT("no"), SelectedEntry->bRequiresArchiveRetentionTuning ? TEXT("yes") : TEXT("no"), SelectedEntry->bPinned ? TEXT("yes") : TEXT("no") - ))); + ); + QueueEntryDetailTextBlock->SetText(FText::FromString(DisplayedSelectedQueueEntryDetailLine)); } else { - QueueEntryDetailTextBlock->SetText(FText::FromString(TEXT("Queue entry detail: no queue entry selected"))); + DisplayedSelectedQueueEntryDetailLine = TEXT("Queue entry detail: no queue entry selected"); + QueueEntryDetailTextBlock->SetText(FText::FromString(DisplayedSelectedQueueEntryDetailLine)); } } if (QueueCountsTextBlock != nullptr) { - QueueCountsTextBlock->SetText(FText::FromString(FString::Printf( + DisplayedQueueCountsLine = FString::Printf( TEXT("Signals: %d | Ready: %d | Deferred: %d | In-progress: %d | Completed: %d"), CachedCoachPanelState.SignalCount, CachedCoachSessionQueueState.ReadyEntryCount, CachedCoachSessionQueueState.DeferredEntryCount, CachedCoachSessionQueueState.InProgressEntryCount, CachedCoachSessionQueueState.CompletedEntryCount - ))); + ); + QueueCountsTextBlock->SetText(FText::FromString(DisplayedQueueCountsLine)); } if (QueueExecutionTextBlock != nullptr) { - QueueExecutionTextBlock->SetText(FText::FromString(FString::Printf( + DisplayedQueueExecutionLine = FString::Printf( TEXT("Execution: queued %d | started %d | completed %d | deferred %d | promoted %d | manual reschedules %d | outstanding deferred: %s | completion gap: %s | archive-aware friction: %s | blocked follow-up friction: %s"), CachedCoachQueueExecutionSummary.QueuedEventCount, CachedCoachQueueExecutionSummary.StartedEventCount, @@ -23936,7 +24123,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() CachedCoachQueueExecutionSummary.bHasCompletionGap ? TEXT("yes") : TEXT("no"), CachedCoachQueueExecutionSummary.bHasArchiveAwareFriction ? TEXT("yes") : TEXT("no"), CachedCoachQueueExecutionSummary.bHasBlockedFollowUpFriction ? TEXT("yes") : TEXT("no") - ))); + ); + QueueExecutionTextBlock->SetText(FText::FromString(DisplayedQueueExecutionLine)); } if (ScheduleHeaderTextBlock != nullptr) { diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index af7e0dd..f358967 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -863,6 +863,18 @@ public: FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface GetDisplayedStartSelectedQueueActionInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardQueueCountsStatusInspectSurface + GetDisplayedQueueCountsStatusInspectSurface() const; + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardSelectedQueueSummaryInspectSurface + GetDisplayedSelectedQueueSummaryInspectSurface() const; + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") + FHyperTwistTrainingCoachDashboardSelectedQueueEntryDetailInspectSurface + GetDisplayedSelectedQueueEntryDetailInspectSurface() const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard") FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface GetDisplayedLastAttemptReviewSummaryInspectSurface() const; @@ -1950,6 +1962,11 @@ private: FString DisplayedQueuedRunLabel; FString DisplayedFollowUpRunLabel; FString DisplayedRecommendedRunLabel; + FString DisplayedQueueStatusLine; + FString DisplayedQueueCountsLine; + FString DisplayedQueueExecutionLine; + FString DisplayedSelectedQueueSummaryLine; + FString DisplayedSelectedQueueEntryDetailLine; FString DisplayedPreviousQueueNavigationLabel; FString DisplayedStartSelectedQueueActionLabel; FString DisplayedNextQueueNavigationLabel; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h index 2208d08..0d1f013 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h @@ -11358,6 +11358,201 @@ struct FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface } }; +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardQueueCountsStatusInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CountsLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ExecutionLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString QueueId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ActiveQueueEntryId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString NextQueueSourceLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 SignalCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 TotalEntryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 PendingEntryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 ReadyEntryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 DeferredEntryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 InProgressEntryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 CompletedEntryCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 QueuedEventCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 StartedEventCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 CompletedEventCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 DeferredEventCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 PromotedEventCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 ManualRescheduleEventCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasOutstandingDeferredWork = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasCompletionGap = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasArchiveAwareFriction = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasBlockedFollowUpFriction = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || !CountsLine.IsEmpty() + || !ExecutionLine.IsEmpty() + || TotalEntryCount > 0 + || QueuedEventCount > 0; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardSelectedQueueSummaryInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString StatusLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedQueueEntryId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedQueueSourceLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedQueueStateLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedQueuePriorityLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedQueueOrdinal; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + float SelectedQueuePriorityScore = 0.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 SelectedQueueEntryIndex = INDEX_NONE; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 TotalQueueEntries = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasSelectedQueueEntry = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSelectedEntryMatchesActiveQueue = false; + + bool IsStructurallyValid() const + { + return !StatusLine.IsEmpty() + || bHasSelectedQueueEntry; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistTrainingCoachDashboardSelectedQueueEntryDetailInspectSurface +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Headline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DetailLine; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SelectedQueueEntryId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EntryHeadline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString FocusDeckId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString FocusMethodSegmentId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SuggestedModeLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SuggestedSelectionPolicyLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DeferredUntilUtc; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DeferralReasonLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 FocusCaseCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasSelectedQueueEntry = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bRequiresFollowUp = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bRequiresArchiveRetentionTuning = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bPinned = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCanStartImmediately = false; + + bool IsStructurallyValid() const + { + return !DetailLine.IsEmpty() + || bHasSelectedQueueEntry; + } +}; + USTRUCT(BlueprintType) struct FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface { diff --git a/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md b/docs/HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md index e12104e..8e55285 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 live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds verification action, selected-queue navigation, and start-selected action enablement inspect surfaces over already-derived live dashboard verification and queue-control presentation state, so gameplay/Blueprint callers can inspect the verify action plus the current queue-navigation and selected-entry launch labels and enablement without scraping widget buttons or reopening queue-control derivation - - the next clean move is to stay on that same live dashboard guidance-consumer lane and land the queue counts/status, selected-queue summary, and selected queue-entry detail inspect surface group rather than drifting back into backend continuity or reopening the already-complete retained-history seam + - the latest landed bounded `Phase 4` packet stays on that same live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds queue counts/status, selected-queue summary, and selected queue-entry detail inspect surfaces over already-derived live dashboard queue overview and selected-entry presentation state, so gameplay/Blueprint callers can inspect the live queue status line, counts/execution posture, current selected-entry summary, and selected-entry detail without scraping widget text or reopening queue-state derivation + - the next clean move is to stay on that same live dashboard guidance-consumer lane and land the schedule horizon status and schedule policy / friction inspect surface pair rather than drifting back into backend continuity or reopening the already-complete retained-history seam - 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_DASHBOARD_LIVE_QUEUE_COUNTS_STATUS_SELECTED_QUEUE_SUMMARY_ENTRY_DETAIL_INSPECT_SURFACE_PACKET_2026-05-09.md b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_QUEUE_COUNTS_STATUS_SELECTED_QUEUE_SUMMARY_ENTRY_DETAIL_INSPECT_SURFACE_PACKET_2026-05-09.md new file mode 100644 index 0000000..ed7dc67 --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE4_DASHBOARD_LIVE_QUEUE_COUNTS_STATUS_SELECTED_QUEUE_SUMMARY_ENTRY_DETAIL_INSPECT_SURFACE_PACKET_2026-05-09.md @@ -0,0 +1,56 @@ +# HyperTwist Phase 4 dashboard live queue counts/status, selected queue summary, and selected queue-entry detail inspect surface packet + +- bounded Phase `4` dashboard-consumer slice +- date: `2026-05-09` + +## Intent + +Stay on the deliberate live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and expose the remaining live queue overview and selected-entry presentation state directly to gameplay and Blueprint callers. + +## Why this packet exists + +The dashboard already derived: + +- the live queue status line for the active coach queue posture +- the live queue counts and queue execution summary lines +- the selected queue-item summary line +- the selected queue-entry detail line + +But that live state still only surfaced through widget text blocks. Callers still had to scrape dashboard text to inspect what the queue overview and current selected entry were actually presenting. + +## What changed + +- added `FHyperTwistTrainingCoachDashboardQueueCountsStatusInspectSurface` +- added `FHyperTwistTrainingCoachDashboardSelectedQueueSummaryInspectSurface` +- added `FHyperTwistTrainingCoachDashboardSelectedQueueEntryDetailInspectSurface` +- added `GetDisplayedQueueCountsStatusInspectSurface()` +- added `GetDisplayedSelectedQueueSummaryInspectSurface()` +- added `GetDisplayedSelectedQueueEntryDetailInspectSurface()` +- retained the exact displayed queue status, counts, execution, selected-summary, and selected-entry detail lines inside the widget so the new inspect surfaces report the same live strings the dashboard is already presenting +- kept the packet bounded to `UHyperTwistCoachDashboardWidget` plus shared surface types, with no dashboard redesign and no backend continuity changes + +## 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 live queue status line, signal/entry counts, and queue execution posture +- the current selected queue-entry summary, source/state/priority posture, and selection ordinal +- the current selected queue-entry detail, suggested mode/policy posture, deferral context, and follow-up/archive/pinning posture + +without scraping dashboard text blocks or reopening queue-state derivation. + +## Validation + +- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln` + - passed with `0 Warning(s), 0 Error(s)` + +## Next clean slice + +Stay on the same live dashboard guidance-consumer lane and land the schedule horizon status and schedule policy / friction inspect surface pair.