Expose dashboard verification and selected queue control surfaces

This commit is contained in:
axiomlogicnexus 2026-05-09 22:08:00 +02:00
parent e53b48c026
commit 5a41e79107
5 changed files with 428 additions and 6 deletions

View file

@ -11376,6 +11376,178 @@ UHyperTwistCoachDashboardWidget::GetDisplayedQueueActionEnablementInspectSurface
return Surface;
}
FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedVerificationActionInspectSurface() const
{
FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface Surface;
Surface.Headline = TEXT("Verification action");
Surface.VerifyLabel = !DisplayedVerificationActionLabel.IsEmpty()
? DisplayedVerificationActionLabel
: TEXT("Verify");
Surface.RepositoryPath = CachedRepositoryRoundTripVerification.ResolvedPath.IsEmpty()
? TEXT("not yet verified")
: CachedRepositoryRoundTripVerification.ResolvedPath;
Surface.LatestNote = CachedRepositoryRoundTripVerification.VerificationNotes.Num() > 0
? CachedRepositoryRoundTripVerification.VerificationNotes[0]
: TEXT("none");
Surface.bVerifyEnabled = true;
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.StatusLine = CachedCoachPanelState.VerificationStatusLine.IsEmpty()
? FString::Printf(
TEXT("%s: %s"),
*Surface.VerifyLabel,
Surface.bDidRoundTripPass ? TEXT("last round-trip passed") : TEXT("ready to run repository round-trip verification"))
: CachedCoachPanelState.VerificationStatusLine;
Surface.DetailLine = FString::Printf(
TEXT("Verification detail: label %s | enabled %s | path %s | save %s | load %s | counts %s | state %s | integrity %s | derived %s | note %s"),
*Surface.VerifyLabel,
Surface.bVerifyEnabled ? TEXT("yes") : TEXT("no"),
*Surface.RepositoryPath,
Surface.bSaveSucceeded ? TEXT("yes") : TEXT("no"),
Surface.bLoadSucceeded ? TEXT("yes") : TEXT("no"),
Surface.bCountsMatched ? TEXT("yes") : TEXT("no"),
Surface.bStateMatched ? TEXT("yes") : TEXT("no"),
Surface.bIntegrityMatched ? TEXT("yes") : TEXT("no"),
Surface.bDerivedMatched ? TEXT("yes") : TEXT("no"),
*Surface.LatestNote);
return Surface;
}
FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedSelectedQueueNavigationInspectSurface() const
{
FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface Surface;
Surface.Headline = TEXT("Selected-queue navigation");
const FHyperTwistTrainingCoachSessionQueueStateEntry* SelectedEntry = FindSelectedQueueEntry();
const bool bNavigationEnabled =
!bHasLiveAttemptTimer && CachedCoachSessionQueueState.Entries.Num() > 1;
Surface.PreviousLabel = !DisplayedPreviousQueueNavigationLabel.IsEmpty()
? DisplayedPreviousQueueNavigationLabel
: TEXT("Prev Queue");
Surface.NextLabel = !DisplayedNextQueueNavigationLabel.IsEmpty()
? DisplayedNextQueueNavigationLabel
: TEXT("Next Queue");
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.SelectedQueueOrdinal =
SelectedEntry != nullptr
? FString::Printf(
TEXT("%d/%d"),
SelectedQueueEntryIndex + 1,
CachedCoachSessionQueueState.Entries.Num())
: TEXT("none");
Surface.SelectedQueueEntryIndex = SelectedQueueEntryIndex;
Surface.TotalQueueEntries = CachedCoachSessionQueueState.Entries.Num();
Surface.bHasSelectedQueueEntry = SelectedEntry != nullptr;
Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer;
Surface.bSelectedEntryMatchesActiveQueue =
SelectedEntry != nullptr
&& SelectedEntry->EntryId == CachedCoachPanelState.ActiveQueueEntryId;
Surface.bPreviousEnabled = bNavigationEnabled;
Surface.bNextEnabled = bNavigationEnabled;
Surface.StatusLine =
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,
SelectedEntry->PriorityLabel.IsEmpty() ? TEXT("n/a") : *SelectedEntry->PriorityLabel,
SelectedEntry->PriorityScore)
: TEXT("Selected queue item: none");
Surface.DetailLine = FString::Printf(
TEXT("%s: %s | %s: %s | active selection: %s | live timer: %s"),
*Surface.PreviousLabel,
Surface.bPreviousEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.NextLabel,
Surface.bNextEnabled ? TEXT("enabled") : TEXT("disabled"),
Surface.bSelectedEntryMatchesActiveQueue ? TEXT("yes") : TEXT("no"),
Surface.bHasLiveAttemptTimer ? TEXT("yes") : TEXT("no"));
return Surface;
}
FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedStartSelectedQueueActionInspectSurface() const
{
FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface Surface;
Surface.Headline = TEXT("Start-selected queue action");
const FHyperTwistTrainingCoachSessionQueueStateEntry* SelectedEntry = FindSelectedQueueEntry();
const bool bSelectedEntryReady =
SelectedEntry != nullptr
&& SelectedEntry->EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Ready;
const bool bSelectedEntryPendingImmediate =
SelectedEntry != nullptr
&& SelectedEntry->EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Pending
&& SelectedEntry->bCanStartImmediately;
Surface.StartSelectedLabel = !DisplayedStartSelectedQueueActionLabel.IsEmpty()
? DisplayedStartSelectedQueueActionLabel
: TEXT("Start Selected");
Surface.SelectedQueueEntryId =
SelectedEntry != nullptr && !SelectedEntry->EntryId.IsEmpty()
? SelectedEntry->EntryId
: TEXT("none");
Surface.SelectedQueueStateLabel =
SelectedEntry != nullptr
? HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(SelectedEntry->EntryState)
: TEXT("n/a");
Surface.SelectedQueueSourceLabel =
SelectedEntry != nullptr && !SelectedEntry->SourceLabel.IsEmpty()
? SelectedEntry->SourceLabel
: TEXT("n/a");
Surface.SelectedQueuePrimaryActionLabel =
SelectedEntry != nullptr && !SelectedEntry->PrimaryActionLabel.IsEmpty()
? SelectedEntry->PrimaryActionLabel
: TEXT("n/a");
Surface.bHasSelectedQueueEntry = SelectedEntry != nullptr;
Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer;
Surface.bSelectedEntryReady = bSelectedEntryReady;
Surface.bSelectedEntryPendingStartImmediate = bSelectedEntryPendingImmediate;
Surface.bStartSelectedEnabled =
!bHasLiveAttemptTimer && (bSelectedEntryReady || bSelectedEntryPendingImmediate);
Surface.StatusLine =
SelectedEntry != nullptr
? FString::Printf(
TEXT("%s: %s | entry %s | state %s"),
*Surface.StartSelectedLabel,
Surface.bStartSelectedEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.SelectedQueueEntryId,
*Surface.SelectedQueueStateLabel)
: FString::Printf(
TEXT("%s: disabled | no queue entry selected"),
*Surface.StartSelectedLabel);
Surface.DetailLine = FString::Printf(
TEXT("Start-selected detail: source %s | action %s | ready %s | pending-immediate %s | live timer %s"),
*Surface.SelectedQueueSourceLabel,
*Surface.SelectedQueuePrimaryActionLabel,
Surface.bSelectedEntryReady ? TEXT("yes") : TEXT("no"),
Surface.bSelectedEntryPendingStartImmediate ? TEXT("yes") : TEXT("no"),
Surface.bHasLiveAttemptTimer ? TEXT("yes") : TEXT("no"));
return Surface;
}
FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedLastAttemptReviewSummaryInspectSurface() const
{
@ -24216,7 +24388,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
if (VerifyButtonLabel != nullptr)
{
VerifyButtonLabel->SetText(FText::FromString(TEXT("Verify")));
DisplayedVerificationActionLabel = TEXT("Verify");
VerifyButtonLabel->SetText(FText::FromString(DisplayedVerificationActionLabel));
}
if (DeferButtonLabel != nullptr)
{
@ -24401,7 +24574,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (PreviousQueueButtonLabel != nullptr)
{
PreviousQueueButtonLabel->SetText(FText::FromString(TEXT("Prev Queue")));
DisplayedPreviousQueueNavigationLabel = TEXT("Prev Queue");
PreviousQueueButtonLabel->SetText(FText::FromString(DisplayedPreviousQueueNavigationLabel));
}
if (PreviousQueueButton != nullptr)
{
@ -24409,7 +24583,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (StartSelectedButtonLabel != nullptr)
{
StartSelectedButtonLabel->SetText(FText::FromString(TEXT("Start Selected")));
DisplayedStartSelectedQueueActionLabel = TEXT("Start Selected");
StartSelectedButtonLabel->SetText(FText::FromString(DisplayedStartSelectedQueueActionLabel));
}
if (StartSelectedButton != nullptr)
{
@ -24422,7 +24597,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (NextQueueButtonLabel != nullptr)
{
NextQueueButtonLabel->SetText(FText::FromString(TEXT("Next Queue")));
DisplayedNextQueueNavigationLabel = TEXT("Next Queue");
NextQueueButtonLabel->SetText(FText::FromString(DisplayedNextQueueNavigationLabel));
}
if (NextQueueButton != nullptr)
{

View file

@ -851,6 +851,18 @@ public:
FHyperTwistTrainingCoachDashboardQueueActionEnablementInspectSurface
GetDisplayedQueueActionEnablementInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface
GetDisplayedVerificationActionInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface
GetDisplayedSelectedQueueNavigationInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface
GetDisplayedStartSelectedQueueActionInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface
GetDisplayedLastAttemptReviewSummaryInspectSurface() const;
@ -1928,6 +1940,7 @@ private:
FString DisplayedRecommendedDeckPreviewLine;
FString DisplayedFollowUpDeckPreviewLine;
FString DisplayedPrimaryActionLabel;
FString DisplayedVerificationActionLabel;
FString DisplayedDeferQueueActionLabel;
FString DisplayedPromoteQueueActionLabel;
FString DisplayedQueueRecoveryActionLabel;
@ -1937,6 +1950,9 @@ private:
FString DisplayedQueuedRunLabel;
FString DisplayedFollowUpRunLabel;
FString DisplayedRecommendedRunLabel;
FString DisplayedPreviousQueueNavigationLabel;
FString DisplayedStartSelectedQueueActionLabel;
FString DisplayedNextQueueNavigationLabel;
FString DisplayedPreviousAttemptNavigationLabel;
FString DisplayedNextAttemptNavigationLabel;
EHyperTwistCoachDashboardGuidancePreviewLane ActiveGuidancePreviewLane =

View file

@ -11183,6 +11183,181 @@ struct FHyperTwistTrainingCoachDashboardQueueActionEnablementInspectSurface
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface
{
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 VerifyLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RepositoryPath;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LatestNote;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bVerifyEnabled = false;
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;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bVerifyEnabled
|| bDidRoundTripPass;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface
{
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 PreviousLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString NextLabel;
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 SelectedQueueOrdinal;
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 bHasLiveAttemptTimer = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSelectedEntryMatchesActiveQueue = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreviousEnabled = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bNextEnabled = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bHasSelectedQueueEntry
|| bPreviousEnabled
|| bNextEnabled;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface
{
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 StartSelectedLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedQueueEntryId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedQueueStateLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedQueueSourceLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedQueuePrimaryActionLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelectedQueueEntry = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasLiveAttemptTimer = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSelectedEntryReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSelectedEntryPendingStartImmediate = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bStartSelectedEnabled = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bStartSelectedEnabled
|| bHasSelectedQueueEntry;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardLastAttemptReviewSummaryInspectSurface
{

View file

@ -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 attempt-review navigation, primary / continue / clear / complete run-control enablement, and queue defer / promote / recovery action enablement inspect surfaces over already-derived live dashboard review-navigation and execution-control presentation state, so gameplay/Blueprint callers can inspect retained attempt-review cycling plus the current run / queue-control labels and enablement without scraping widget buttons or reopening execution-control derivation
- the next clean move is to stay on that same live dashboard guidance-consumer lane and land the verification action, selected-queue navigation, and start-selected action enablement 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 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 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

View file

@ -0,0 +1,55 @@
# HyperTwist Phase 4 dashboard live verification, queue navigation, and start-selected action enablement 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 verification and selected-queue execution controls directly to gameplay and Blueprint callers.
## Why this packet exists
The dashboard already derived:
- the displayed `Verify` action label and the retained repository-verification posture behind it
- the displayed previous/next selected-queue navigation labels and their enablement posture
- the displayed `Start Selected` queue-action label and its selected-entry actionability posture
But that live state still only surfaced through widget buttons. Callers still had to scrape button labels or enabled state to inspect what the dashboard was currently presenting.
## What changed
- added `FHyperTwistTrainingCoachDashboardVerificationActionInspectSurface`
- added `FHyperTwistTrainingCoachDashboardSelectedQueueNavigationInspectSurface`
- added `FHyperTwistTrainingCoachDashboardStartSelectedQueueActionInspectSurface`
- added `GetDisplayedVerificationActionInspectSurface()`
- added `GetDisplayedSelectedQueueNavigationInspectSurface()`
- added `GetDisplayedStartSelectedQueueActionInspectSurface()`
- retained the exact displayed verify, previous-queue, next-queue, and start-selected labels 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 verify action label, latest round-trip posture, and button availability
- the current selected-queue navigation labels, selection summary, and navigation enablement posture
- the start-selected action label plus the selected-entry runnable posture
without scraping widget buttons or reopening queue-control 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 queue counts/status, selected-queue summary, and selected queue-entry detail inspect surface group.