Expose dashboard drill follow-up history navigation surface

This commit is contained in:
axiomlogicnexus 2026-05-10 02:05:46 +02:00
parent f595934829
commit 4fd3991016
5 changed files with 267 additions and 4 deletions

View file

@ -8325,6 +8325,122 @@ UHyperTwistCoachDashboardWidget::GetSelectedMethodDrillFollowUpHistoryInspectSur
return Surface;
}
FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryNavigationInspectSurface
UHyperTwistCoachDashboardWidget::GetDisplayedMethodDrillFollowUpHistoryNavigationInspectSurface() const
{
FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryNavigationInspectSurface Surface;
Surface.Headline = TEXT("Method-drill follow-up history navigation");
const FHyperTwistCoachDashboardMethodDrillFollowUpWeighting Weighting =
BuildMethodDrillFollowUpWeighting();
const FHyperTwistCoachDashboardMethodDrillFollowUpHistoryEntry* SelectedEntry =
SelectedMethodDrillFollowUpHistoryIndex >= 0
&& SelectedMethodDrillFollowUpHistoryIndex < MethodDrillFollowUpHistoryEntries.Num()
? &MethodDrillFollowUpHistoryEntries[SelectedMethodDrillFollowUpHistoryIndex]
: nullptr;
const bool bNavigationEnabled = MethodDrillFollowUpHistoryEntries.Num() > 1;
Surface.PreviousLabel = !DisplayedPreviousMethodDrillFollowUpNavigationLabel.IsEmpty()
? DisplayedPreviousMethodDrillFollowUpNavigationLabel
: TEXT("Prev Drill Follow-Up");
Surface.NextLabel = !DisplayedNextMethodDrillFollowUpNavigationLabel.IsEmpty()
? DisplayedNextMethodDrillFollowUpNavigationLabel
: TEXT("Next Drill Follow-Up");
Surface.SelectedEntryIndex = SelectedMethodDrillFollowUpHistoryIndex;
Surface.HistoryEntryCount = MethodDrillFollowUpHistoryEntries.Num();
Surface.bHasSelectedEntry =
SelectedEntry != nullptr && SelectedEntry->IsStructurallyValid();
Surface.bSelectedEntryIsLatest =
Surface.bHasSelectedEntry
&& SelectedMethodDrillFollowUpHistoryIndex
== MethodDrillFollowUpHistoryEntries.Num() - 1;
Surface.bPreviousEnabled = bNavigationEnabled;
Surface.bNextEnabled = bNavigationEnabled;
Surface.bHasHistoryWeighting = Weighting.IsStructurallyValid();
Surface.bPreferDrillFollowUp = Weighting.bPreferDrillFollowUp;
Surface.bPreferCoachHandoff = Weighting.bPreferCoachHandoff;
Surface.bHasUpstreamStructureSignal = Weighting.bHasUpstreamStructureSignal;
Surface.OutcomePreferenceLine = !Weighting.IsStructurallyValid()
? TEXT("no retained drill follow-up history yet")
: (Weighting.bPreferDrillFollowUp
? (Weighting.bUsedUpstreamNarrowStructureSignal
? TEXT("retained drill-follow-up packet structure history favors staying narrow with drill follow-up")
: TEXT("retained drill history favors staying narrow with drill follow-up"))
: (Weighting.bPreferCoachHandoff
? (Weighting.bUsedUpstreamBroadStructureSignal
? TEXT("retained drill-follow-up packet structure history favors handing control back to broader coach guidance")
: TEXT("retained drill history favors handing control back to broader coach guidance"))
: TEXT("retained drill history is balanced")));
if (!Surface.bHasSelectedEntry)
{
Surface.SelectedEntryOrdinal = TEXT("none");
Surface.RecordedAtUtc = TEXT("n/a");
Surface.StageLabel = TEXT("n/a");
Surface.DiagnosticStateLabel = TEXT("n/a");
Surface.RecommendedReviewGradeLabel = TEXT("n/a");
Surface.SuggestedModeLabel = TEXT("n/a");
Surface.PacketStructureLabel = TEXT("n/a");
Surface.PacketStanceLabel = TEXT("n/a");
Surface.StatusLine =
TEXT("Drill follow-up navigation: no retained drill follow-up outcomes recorded yet.");
Surface.DetailLine = FString::Printf(
TEXT("%s: %s | %s: %s | preference: %s | selected latest: no"),
*Surface.PreviousLabel,
Surface.bPreviousEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.NextLabel,
Surface.bNextEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.OutcomePreferenceLine);
return Surface;
}
Surface.SelectedEntryOrdinal = FString::Printf(
TEXT("%d/%d"),
SelectedMethodDrillFollowUpHistoryIndex + 1,
MethodDrillFollowUpHistoryEntries.Num());
Surface.RecordedAtUtc = SelectedEntry->RecordedAtUtc.IsEmpty()
? TEXT("n/a")
: SelectedEntry->RecordedAtUtc;
Surface.StageLabel =
SelectedEntry->StageLabel.IsEmpty() ? TEXT("n/a") : SelectedEntry->StageLabel;
Surface.DiagnosticStateLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->DiagnosticState);
Surface.RecommendedReviewGradeLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->RecommendedReviewGrade);
Surface.SuggestedModeLabel =
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
SelectedEntry->SuggestedMode);
Surface.PacketStructureLabel =
SelectedEntry->PacketStructureLabel.IsEmpty()
? TEXT("default")
: SelectedEntry->PacketStructureLabel;
Surface.PacketStanceLabel =
SelectedEntry->PacketStanceLabel.IsEmpty()
? TEXT("none")
: SelectedEntry->PacketStanceLabel;
Surface.StatusLine = FString::Printf(
TEXT("Drill follow-up navigation: selected %s | Stage: %s | review %s | packet: %s | Recorded: %s"),
*Surface.SelectedEntryOrdinal,
*Surface.StageLabel,
*Surface.RecommendedReviewGradeLabel,
*Surface.PacketStructureLabel,
*Surface.RecordedAtUtc);
Surface.DetailLine = FString::Printf(
TEXT("%s: %s | %s: %s | state: %s | mode: %s | preference: %s | stance: %s | selected latest: %s"),
*Surface.PreviousLabel,
Surface.bPreviousEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.NextLabel,
Surface.bNextEnabled ? TEXT("enabled") : TEXT("disabled"),
*Surface.DiagnosticStateLabel,
*Surface.SuggestedModeLabel,
*Surface.OutcomePreferenceLine,
*Surface.PacketStanceLabel,
Surface.bSelectedEntryIsLatest ? TEXT("yes") : TEXT("no"));
return Surface;
}
FHyperTwistTrainingCoachDashboardHandoffHistoryInspectSurface
UHyperTwistCoachDashboardWidget::GetSelectedHandoffHistoryInspectSurface() const
{
@ -24348,8 +24464,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (PreviousMethodDrillFollowUpHistoryButtonLabel != nullptr)
{
DisplayedPreviousMethodDrillFollowUpNavigationLabel = TEXT("Prev Drill Follow-Up");
PreviousMethodDrillFollowUpHistoryButtonLabel->SetText(FText::FromString(
TEXT("Prev Drill Follow-Up")));
DisplayedPreviousMethodDrillFollowUpNavigationLabel));
}
if (PreviousMethodDrillFollowUpHistoryButton != nullptr)
{
@ -24358,8 +24475,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
if (NextMethodDrillFollowUpHistoryButtonLabel != nullptr)
{
DisplayedNextMethodDrillFollowUpNavigationLabel = TEXT("Next Drill Follow-Up");
NextMethodDrillFollowUpHistoryButtonLabel->SetText(FText::FromString(
TEXT("Next Drill Follow-Up")));
DisplayedNextMethodDrillFollowUpNavigationLabel));
}
if (NextMethodDrillFollowUpHistoryButton != nullptr)
{

View file

@ -767,6 +767,10 @@ public:
FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryInspectSurface
GetSelectedMethodDrillFollowUpHistoryInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryNavigationInspectSurface
GetDisplayedMethodDrillFollowUpHistoryNavigationInspectSurface() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingCoachDashboardHandoffHistoryInspectSurface
GetSelectedHandoffHistoryInspectSurface() const;
@ -2014,6 +2018,8 @@ private:
FString DisplayedNextMethodDrillRecoveryNavigationLabel;
FString DisplayedPreviousMethodDrillRecoveryMemoryNavigationLabel;
FString DisplayedNextMethodDrillRecoveryMemoryNavigationLabel;
FString DisplayedPreviousMethodDrillFollowUpNavigationLabel;
FString DisplayedNextMethodDrillFollowUpNavigationLabel;
FString DisplayedPreviousAttemptNavigationLabel;
FString DisplayedNextAttemptNavigationLabel;
EHyperTwistCoachDashboardGuidancePreviewLane ActiveGuidancePreviewLane =

View file

@ -9298,6 +9298,93 @@ struct FHyperTwistTrainingCoachDashboardMethodDrillRecoveryMemoryHistoryNavigati
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryNavigationInspectSurface
{
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 SelectedEntryOrdinal;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecordedAtUtc;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString StageLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DiagnosticStateLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecommendedReviewGradeLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SuggestedModeLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PacketStructureLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PacketStanceLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString OutcomePreferenceLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 SelectedEntryIndex = INDEX_NONE;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 HistoryEntryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelectedEntry = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSelectedEntryIsLatest = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreviousEnabled = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bNextEnabled = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasHistoryWeighting = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreferDrillFollowUp = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreferCoachHandoff = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasUpstreamStructureSignal = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !DetailLine.IsEmpty()
|| bHasSelectedEntry
|| bPreviousEnabled
|| bNextEnabled;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryInspectSurface
{

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 retained-history navigation/control lane and adds the method-drill recovery memory history navigation control inspect surface over already-retained upstream drill-recovery memory snapshots, so gameplay/Blueprint callers can inspect the live prev/next drill-memory labels, enablement posture, selected retained memory ordinal, and action/handoff/bias/latest-selection context without scraping button text or reopening retained-history derivation
- the next clean move is to continue that same retained-history navigation/control lane and expose the method-drill follow-up history navigation control surface rather than drifting back into backend continuity or reopening the already-inspectable history detail seams
- the latest landed bounded `Phase 4` packet stays on that same retained-history navigation/control lane and adds the method-drill follow-up history navigation control inspect surface over already-retained drill follow-up outcomes, so gameplay/Blueprint callers can inspect the live prev/next drill-follow-up labels, enablement posture, selected retained follow-up ordinal, and review/preference/latest-selection context without scraping button text or reopening retained-history derivation
- the next clean move is to continue that same retained-history navigation/control lane and expose the handoff history navigation control surface rather than drifting back into backend continuity or reopening the already-inspectable history detail seams
- 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

View file

@ -0,0 +1,52 @@
# HyperTwist Phase 4 dashboard method-drill follow-up history navigation control inspect surface packet
- bounded Phase `4` dashboard-consumer slice
- date: `2026-05-10`
## Intent
Stay on the retained-history navigation/control lane inside `UHyperTwistCoachDashboardWidget` and expose the method-drill follow-up history navigation controls directly to gameplay and Blueprint callers.
## Why this packet exists
The dashboard already derived and displayed:
- the previous drill-follow-up-history button label
- the next drill-follow-up-history button label
- the enablement posture for both controls
But that control state still only surfaced through button text and button enabled state. Callers still had to inspect widget controls directly to understand whether retained drill-follow-up navigation is available and which retained follow-up outcome is currently selected.
## What changed
- added `FHyperTwistTrainingCoachDashboardMethodDrillFollowUpHistoryNavigationInspectSurface`
- added `GetDisplayedMethodDrillFollowUpHistoryNavigationInspectSurface()`
- retained the exact displayed previous/next drill-follow-up-history labels inside the widget so the new inspect surface reports 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 previous/next drill-follow-up-history labels
- whether drill-follow-up-history navigation is currently enabled
- the selected retained follow-up ordinal, recorded time, stage label, diagnostic state, and review grade
- the retained outcome-preference line, packet structure / stance posture, and latest-selection posture
without scraping button text or reopening retained-history derivation.
## Validation
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
- passed with `0 Warning(s), 0 Error(s)`
## Next clean slice
Stay on the retained-history navigation/control lane and expose the handoff history navigation control surface.