Expose gameplay selector split-phase fusion preview surface

This commit is contained in:
axiomlogicnexus 2026-05-08 21:39:47 +02:00
parent b91829af87
commit 17a323432f
9 changed files with 784 additions and 2 deletions

View file

@ -10476,6 +10476,341 @@ UHyperTwistTrainingCoachLibrary::
return Surface;
}
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
UHyperTwistTrainingCoachLibrary::
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
const FHyperTwistTrainingRunState& RunState,
const FString& SelectorId,
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
OptionLaunchRequestPreviewSurface
)
{
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseNormalizationSummaryPreviewSurface
NormalizationSummaryPreviewSurface =
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseNormalizationSummaryPreviewSurface(
RunState,
SelectorId,
OptionMenuSurface,
OptionLaunchRequestPreviewSurface
);
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhasePhaseIdLabelFallbackProvenancePreviewSurface
LabelProvenancePreviewSurface =
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhasePhaseIdLabelFallbackProvenancePreviewSurface(
RunState,
SelectorId,
OptionMenuSurface,
OptionLaunchRequestPreviewSurface
);
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseDuplicatePruningSurvivorProvenancePreviewSurface
DuplicatePruningPreviewSurface =
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseDuplicatePruningSurvivorProvenancePreviewSurface(
RunState,
SelectorId,
OptionMenuSurface,
OptionLaunchRequestPreviewSurface
);
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
Surface;
Surface.SelectorId = NormalizationSummaryPreviewSurface.SelectorId;
Surface.SelectorLabel = NormalizationSummaryPreviewSurface.SelectorLabel;
Surface.BindingLabel = NormalizationSummaryPreviewSurface.BindingLabel;
Surface.Headline =
TEXT("Generated Mode Selector Option Owned-Execution Split-Phase Raw-Row/Normalized-Phase Fusion Preview");
Surface.StatusLine = NormalizationSummaryPreviewSurface.StatusLine;
Surface.NormalizationSummaryLine =
NormalizationSummaryPreviewSurface.NormalizationSummaryLine;
Surface.LabelFallbackSummaryLine =
NormalizationSummaryPreviewSurface.LabelFallbackSummaryLine;
Surface.PreviewPostureSummaryLine =
NormalizationSummaryPreviewSurface.PreviewPostureSummaryLine;
Surface.CurrentSelectionFusionLine =
NormalizationSummaryPreviewSurface.CurrentSelectionNormalizationSummaryLine;
Surface.DetailLine = NormalizationSummaryPreviewSurface.DetailLine;
Surface.DirectExactOptionCount =
NormalizationSummaryPreviewSurface.DirectExactOptionCount;
Surface.GeneratedExactOptionCount =
NormalizationSummaryPreviewSurface.GeneratedExactOptionCount;
Surface.BlockedOptionCount =
NormalizationSummaryPreviewSurface.BlockedOptionCount;
Surface.UnavailableOptionCount =
NormalizationSummaryPreviewSurface.UnavailableOptionCount;
Surface.RawSplitPhaseDefinitionCount =
NormalizationSummaryPreviewSurface.RawSplitPhaseDefinitionCount;
Surface.SurvivorPhaseCount =
NormalizationSummaryPreviewSurface.SurvivorPhaseCount;
Surface.DuplicatePrunedPhaseCount =
NormalizationSummaryPreviewSurface.DuplicatePrunedPhaseCount;
Surface.InvalidRawDefinitionCount =
NormalizationSummaryPreviewSurface.InvalidRawDefinitionCount;
Surface.ExplicitLabelPhaseCount =
NormalizationSummaryPreviewSurface.ExplicitLabelPhaseCount;
Surface.FallbackLabelPhaseCount =
NormalizationSummaryPreviewSurface.FallbackLabelPhaseCount;
Surface.OptionsWithFallbackLabelCount =
NormalizationSummaryPreviewSurface.OptionsWithFallbackLabelCount;
Surface.OptionsWithDuplicatePruningCount =
NormalizationSummaryPreviewSurface.OptionsWithDuplicatePruningCount;
Surface.OptionsWithInvalidRawDefinitionsCount =
NormalizationSummaryPreviewSurface.OptionsWithInvalidRawDefinitionsCount;
Surface.bHasSelector = NormalizationSummaryPreviewSurface.bHasSelector;
Surface.bHasOwnedExecutionSplitPhaseFusionPreviewOptions =
NormalizationSummaryPreviewSurface
.bHasOwnedExecutionSplitPhaseNormalizationSummaryPreviewOptions;
Surface.bHasDirectSplitPhaseFusionPreviewOptions =
NormalizationSummaryPreviewSurface
.bHasDirectSplitPhaseNormalizationSummaryPreviewOptions;
Surface.bHasGeneratedSplitPhaseFusionPreviewOptions =
NormalizationSummaryPreviewSurface
.bHasGeneratedSplitPhaseNormalizationSummaryPreviewOptions;
Surface.bHasBlockedSplitPhaseFusionPreviewOptions =
NormalizationSummaryPreviewSurface
.bHasBlockedSplitPhaseNormalizationSummaryPreviewOptions;
Surface.bCurrentSelectionHasExactSplitPhaseFusionPreview =
NormalizationSummaryPreviewSurface
.bCurrentSelectionHasExactSplitPhaseNormalizationSummaryPreview;
Surface.bCurrentSelectionRetainsActiveDeckSplitPhaseFusion =
NormalizationSummaryPreviewSurface
.bCurrentSelectionRetainsActiveDeckSplitPhaseNormalizationSummary;
Surface.bCurrentSelectionHasFallbackLabels =
NormalizationSummaryPreviewSurface.bCurrentSelectionHasFallbackLabels;
Surface.bCurrentSelectionHasDuplicatePrunedPhases =
NormalizationSummaryPreviewSurface
.bCurrentSelectionHasDuplicatePrunedPhases;
Surface.bCurrentSelectionHasInvalidRawDefinitions =
NormalizationSummaryPreviewSurface
.bCurrentSelectionHasInvalidRawDefinitions;
if (!SelectorId.IsEmpty())
{
Surface.Headline = OptionMenuSurface.SelectorLabel.IsEmpty()
? FString::Printf(
TEXT("Generated Mode Selector Option Owned-Execution Split-Phase Raw-Row/Normalized-Phase Fusion Preview: %s"),
*SelectorId
)
: FString::Printf(
TEXT("Generated Mode Selector Option Owned-Execution Split-Phase Raw-Row/Normalized-Phase Fusion Preview: %s"),
*OptionMenuSurface.SelectorLabel
);
}
TMap<FString, int32> LabelEntryIndexByOptionId;
for (int32 EntryIndex = 0;
EntryIndex < LabelProvenancePreviewSurface.OptionEntries.Num();
++EntryIndex)
{
LabelEntryIndexByOptionId.FindOrAdd(
LabelProvenancePreviewSurface.OptionEntries[EntryIndex].OptionId
) = EntryIndex;
}
const auto BuildFusionUnavailableLabelLine = [](
const FString& Reason
) -> FString
{
return Reason.IsEmpty()
? TEXT("Normalized label provenance on execute: unavailable")
: Reason;
};
for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseDuplicatePruningSurvivorProvenancePreviewEntrySurface&
DuplicateEntry : DuplicatePruningPreviewSurface.OptionEntries)
{
const int32* LabelEntryIndex = LabelEntryIndexByOptionId.Find(
DuplicateEntry.OptionId
);
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhasePhaseIdLabelFallbackProvenancePreviewEntrySurface*
LabelEntry = LabelEntryIndex != nullptr
? &LabelProvenancePreviewSurface.OptionEntries[*LabelEntryIndex]
: nullptr;
TMap<FString, int32> LabelPhaseIndexByPhaseId;
if (LabelEntry != nullptr)
{
for (int32 PhaseIndex = 0;
PhaseIndex < LabelEntry->PhaseEntries.Num();
++PhaseIndex)
{
LabelPhaseIndexByPhaseId.FindOrAdd(
LabelEntry->PhaseEntries[PhaseIndex].PhaseId
) = PhaseIndex;
}
}
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewEntrySurface
Entry;
Entry.OptionId = DuplicateEntry.OptionId;
Entry.Label = DuplicateEntry.Label;
Entry.OptionValue = DuplicateEntry.OptionValue;
Entry.LaunchRequestPreviewKind = DuplicateEntry.LaunchRequestPreviewKind;
Entry.RawSplitPhaseCountLine = DuplicateEntry.RawSplitPhaseCountLine;
Entry.SurvivorCountLine = DuplicateEntry.SurvivorCountLine;
Entry.DuplicatePruningLine = DuplicateEntry.DuplicatePruningLine;
Entry.InvalidDefinitionLine = DuplicateEntry.InvalidDefinitionLine;
Entry.LabelProvenanceLine = LabelEntry != nullptr
? LabelEntry->LabelProvenanceLine
: TEXT("Label provenance on execute: unavailable");
Entry.FallbackPhaseIdLine = LabelEntry != nullptr
? LabelEntry->FallbackPhaseIdLine
: TEXT("Phase-id fallback labels on execute: unavailable");
Entry.RawSplitPhaseCount = DuplicateEntry.RawSplitPhaseCount;
Entry.SurvivorPhaseCount = DuplicateEntry.SurvivorPhaseCount;
Entry.DuplicatePrunedPhaseCount = DuplicateEntry.DuplicatePrunedPhaseCount;
Entry.InvalidRawDefinitionCount = DuplicateEntry.InvalidRawDefinitionCount;
Entry.ExplicitLabelPhaseCount = LabelEntry != nullptr
? LabelEntry->ExplicitLabelPhaseCount
: 0;
Entry.FallbackLabelPhaseCount = LabelEntry != nullptr
? LabelEntry->FallbackLabelPhaseCount
: 0;
Entry.bMatchesCurrentSelection = DuplicateEntry.bMatchesCurrentSelection;
Entry.bStartsOwnedCaseImmediately =
DuplicateEntry.bStartsOwnedCaseImmediately;
Entry.bHasExactFusionPreview =
DuplicateEntry.bHasExactSplitPhaseDuplicatePruningPreview
&& LabelEntry != nullptr
&& LabelEntry->bHasExactSplitPhaseLabelProvenancePreview;
Entry.bRetainsActiveDeckSplitPhaseFusion =
DuplicateEntry.bRetainsActiveDeckSplitPhaseDuplicatePruningProvenance
&& LabelEntry != nullptr
&& LabelEntry->bRetainsActiveDeckSplitPhaseLabelProvenance;
Entry.bHasFallbackLabels = LabelEntry != nullptr
&& LabelEntry->bHasFallbackLabels;
Entry.bHasDuplicatePrunedPhases =
DuplicateEntry.bHasDuplicatePrunedPhases;
Entry.bHasInvalidRawDefinitions =
DuplicateEntry.bHasInvalidRawDefinitions;
Entry.bPreviewBlocked = DuplicateEntry.bPreviewBlocked;
Entry.bCanPreview = DuplicateEntry.bCanPreview;
Entry.PreviewPostureLine = DuplicateEntry.SplitPhaseSourceLine.IsEmpty()
? DuplicateEntry.PreviewStabilityLine
: FString::Printf(
TEXT("Preview posture on execute: %s | %s"),
*DuplicateEntry.PreviewStabilityLine,
*DuplicateEntry.SplitPhaseSourceLine
);
Entry.FusionSummaryLine = FString::Printf(
TEXT("Raw-row / normalized-phase fusion on execute: %d raw rows | %d survivors | %d explicit labels | %d phase-id fallbacks"),
Entry.RawSplitPhaseCount,
Entry.SurvivorPhaseCount,
Entry.ExplicitLabelPhaseCount,
Entry.FallbackLabelPhaseCount
);
for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseDuplicatePruningSurvivorProvenancePreviewRawPhaseEntrySurface&
RawRow : DuplicateEntry.RawPhaseEntries)
{
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewRowSurface
FusedRow;
FusedRow.PhaseId = RawRow.PhaseId;
FusedRow.SourceLabel = RawRow.SourceLabel;
FusedRow.RawOrder = RawRow.RawOrder;
FusedRow.EvaluationOrder = RawRow.EvaluationOrder;
FusedRow.NormalizedOrder = RawRow.NormalizedOrder;
FusedRow.RawDefinitionLine = RawRow.RawDefinitionLine;
FusedRow.NormalizationOutcomeLine = RawRow.NormalizationOutcomeLine;
FusedRow.DuplicatePruningProvenanceLine =
RawRow.DuplicatePruningProvenanceLine;
FusedRow.bSourceLabelWasExplicit = RawRow.bSourceLabelWasExplicit;
FusedRow.bSurvivesNormalization = RawRow.bSurvivesNormalization;
FusedRow.bDroppedBecauseDuplicate = RawRow.bDroppedBecauseDuplicate;
FusedRow.bDroppedBecauseInvalid = RawRow.bDroppedBecauseInvalid;
FusedRow.bCanPreview = RawRow.bCanPreview;
if (RawRow.bSurvivesNormalization
&& LabelEntry != nullptr
&& LabelPhaseIndexByPhaseId.Contains(RawRow.PhaseId))
{
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhasePhaseIdLabelFallbackProvenancePreviewPhaseEntrySurface&
LabelPhase =
LabelEntry->PhaseEntries[LabelPhaseIndexByPhaseId[RawRow.PhaseId]];
FusedRow.NormalizedOrder = LabelPhase.Order;
FusedRow.NormalizedLabel = LabelPhase.NormalizedLabel;
FusedRow.LabelProvenanceLine = LabelPhase.LabelProvenanceLine;
FusedRow.bLabelFallsBackToPhaseId =
LabelPhase.bLabelFallsBackToPhaseId;
FusedRow.bHasNormalizedPhaseDetail = true;
FusedRow.FusedRowLine = FString::Printf(
TEXT("Raw row / normalized phase fusion on execute: evaluation #%d survives as normalized phase #%d with label %s (%s)."),
FusedRow.EvaluationOrder,
FusedRow.NormalizedOrder,
*FusedRow.NormalizedLabel,
*RawRow.PhaseId
);
}
else if (RawRow.bSurvivesNormalization)
{
FusedRow.NormalizedLabel = RawRow.SurvivorNormalizedLabel;
FusedRow.LabelProvenanceLine = RawRow.SourceLabel.IsEmpty()
? FString::Printf(
TEXT("Normalized label provenance on execute: phase-id fallback retained because the source label is empty (%s)"),
*RawRow.PhaseId
)
: FString::Printf(
TEXT("Normalized label provenance on execute: explicit source label retained (%s)"),
*RawRow.SourceLabel
);
FusedRow.bLabelFallsBackToPhaseId = RawRow.SourceLabel.IsEmpty();
FusedRow.bHasNormalizedPhaseDetail = !FusedRow.NormalizedLabel.IsEmpty();
FusedRow.FusedRowLine = FString::Printf(
TEXT("Raw row / normalized phase fusion on execute: evaluation #%d survives as normalized phase #%d with label %s (%s)."),
FusedRow.EvaluationOrder,
FusedRow.NormalizedOrder,
*FusedRow.NormalizedLabel,
*RawRow.PhaseId
);
}
else if (RawRow.bDroppedBecauseDuplicate)
{
FusedRow.LabelProvenanceLine = FString::Printf(
TEXT("Normalized label provenance on execute: unavailable for this raw row because phase id %s was duplicate-pruned before normalized phase detail was retained."),
*RawRow.PhaseId
);
FusedRow.FusedRowLine = FString::Printf(
TEXT("Raw row / normalized phase fusion on execute: evaluation #%d is duplicate-pruned, so fused normalized phase detail remains attached to the first valid surviving row for %s."),
FusedRow.EvaluationOrder,
*RawRow.PhaseId
);
}
else if (RawRow.bDroppedBecauseInvalid)
{
FusedRow.LabelProvenanceLine =
TEXT("Normalized label provenance on execute: unavailable for this raw row because structurally invalid definitions are skipped before normalized phase detail is retained.");
FusedRow.FusedRowLine = FString::Printf(
TEXT("Raw row / normalized phase fusion on execute: evaluation #%d never reaches normalized phase detail because the raw row is structurally invalid."),
FusedRow.EvaluationOrder
);
}
else
{
FusedRow.LabelProvenanceLine =
BuildFusionUnavailableLabelLine(TEXT("Normalized label provenance on execute: unavailable"));
FusedRow.FusedRowLine =
TEXT("Raw row / normalized phase fusion on execute: unavailable");
}
FusedRow.DetailLine = FString::Printf(
TEXT("%s | %s | %s"),
*FusedRow.NormalizationOutcomeLine,
*FusedRow.LabelProvenanceLine,
*FusedRow.FusedRowLine
);
Entry.FusedRows.Add(MoveTemp(FusedRow));
}
Entry.DetailLine = FString::Printf(
TEXT("%s | %s | %s"),
*Entry.PreviewPostureLine,
*Entry.FusionSummaryLine,
*Entry.LabelProvenanceLine
);
Surface.OptionEntries.Add(MoveTemp(Entry));
}
return Surface;
}
FHyperTwistTrainingCoachQueueControlSurface
UHyperTwistTrainingCoachLibrary::DeriveCoachQueueControlSurface(
const FHyperTwistTrainingCoachSessionQueueState& QueueState,

View file

@ -1138,6 +1138,25 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwne
);
}
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
const FString& SelectorId
) const
{
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface
OptionLaunchRequestPreviewSurface =
GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId);
return UHyperTwistTrainingCoachLibrary::
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
CachedRunState,
SelectorId,
OptionMenuSurface,
OptionLaunchRequestPreviewSurface
);
}
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
const int32 MaxCases,
const FString& StartActionSourceLabel

View file

@ -1119,6 +1119,25 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwn
);
}
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
const FString& SelectorId
) const
{
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface
OptionLaunchRequestPreviewSurface =
GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId);
return UHyperTwistTrainingCoachLibrary::
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
CachedRunState,
SelectorId,
OptionMenuSurface,
OptionLaunchRequestPreviewSurface
);
}
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
const int32 MaxCases
)

View file

@ -917,4 +917,14 @@ public:
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
OptionLaunchRequestPreviewSurface
);
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
static FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
const FHyperTwistTrainingRunState& RunState,
const FString& SelectorId,
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
OptionLaunchRequestPreviewSurface
);
};

View file

@ -380,6 +380,12 @@ public:
const FString& SelectorId
) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
const FString& SelectorId
) const;
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingRunState StartCoachRecommendedRun(
int32 MaxCases,

View file

@ -361,6 +361,12 @@ public:
const FString& SelectorId
) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(
const FString& SelectorId
) const;
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);

View file

@ -13047,3 +13047,300 @@ struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPha
|| bHasOwnedExecutionSplitPhaseNormalizationSummaryPreviewOptions;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewRowSurface
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PhaseId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SourceLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString NormalizedLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RawOrder = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 EvaluationOrder = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 NormalizedOrder = -1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RawDefinitionLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString NormalizationOutcomeLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DuplicatePruningProvenanceLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LabelProvenanceLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString FusedRowLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSourceLabelWasExplicit = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSurvivesNormalization = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bDroppedBecauseDuplicate = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bDroppedBecauseInvalid = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bLabelFallsBackToPhaseId = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasNormalizedPhaseDetail = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCanPreview = false;
bool IsStructurallyValid() const
{
return !PhaseId.IsEmpty()
|| !RawDefinitionLine.IsEmpty()
|| !LabelProvenanceLine.IsEmpty()
|| !FusedRowLine.IsEmpty()
|| bCanPreview;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewEntrySurface
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString OptionId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Label;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString OptionValue;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind LaunchRequestPreviewKind =
EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RawSplitPhaseCountLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SurvivorCountLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DuplicatePruningLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString InvalidDefinitionLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LabelProvenanceLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString FallbackPhaseIdLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString FusionSummaryLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PreviewPostureLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewRowSurface>
FusedRows;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RawSplitPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 SurvivorPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 DuplicatePrunedPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 InvalidRawDefinitionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ExplicitLabelPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 FallbackLabelPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bMatchesCurrentSelection = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bStartsOwnedCaseImmediately = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasExactFusionPreview = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bRetainsActiveDeckSplitPhaseFusion = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasFallbackLabels = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasDuplicatePrunedPhases = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasInvalidRawDefinitions = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreviewBlocked = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCanPreview = false;
bool IsStructurallyValid() const
{
return !OptionId.IsEmpty()
|| !Label.IsEmpty()
|| !RawSplitPhaseCountLine.IsEmpty()
|| !FusionSummaryLine.IsEmpty()
|| !PreviewPostureLine.IsEmpty()
|| LaunchRequestPreviewKind
!= EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None
|| bCanPreview;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectorId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectorLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString BindingLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Headline;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString StatusLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString NormalizationSummaryLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LabelFallbackSummaryLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PreviewPostureSummaryLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString CurrentSelectionFusionLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewEntrySurface>
OptionEntries;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 DirectExactOptionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 GeneratedExactOptionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 BlockedOptionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 UnavailableOptionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RawSplitPhaseDefinitionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 SurvivorPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 DuplicatePrunedPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 InvalidRawDefinitionCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ExplicitLabelPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 FallbackLabelPhaseCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 OptionsWithFallbackLabelCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 OptionsWithDuplicatePruningCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 OptionsWithInvalidRawDefinitionsCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasSelector = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasOwnedExecutionSplitPhaseFusionPreviewOptions = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasDirectSplitPhaseFusionPreviewOptions = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasGeneratedSplitPhaseFusionPreviewOptions = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasBlockedSplitPhaseFusionPreviewOptions = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCurrentSelectionHasExactSplitPhaseFusionPreview = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCurrentSelectionRetainsActiveDeckSplitPhaseFusion = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCurrentSelectionHasFallbackLabels = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCurrentSelectionHasDuplicatePrunedPhases = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCurrentSelectionHasInvalidRawDefinitions = false;
bool IsStructurallyValid() const
{
return !StatusLine.IsEmpty()
|| !SelectorId.IsEmpty()
|| OptionEntries.Num() > 0
|| bHasSelector
|| bHasOwnedExecutionSplitPhaseFusionPreviewOptions;
}
};

View file

@ -68,8 +68,8 @@ Current correction call from the source-exposed audit and current execution refr
- the imported generated-mode gap is closed; request/config/selection plumbing and the bounded clean-room executor are already landed in first-party code
- 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 latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector option owned execution split-phase normalization summary surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can inspect raw definitions, survivors, label fallback, and blocked preview posture from one surface instead of merging the existing split-phase normalization previews themselves
- the current next bounded packet is to expose one thin generated-mode selector option owned execution split-phase raw-row / normalized-phase fusion preview surface on those same two consumer surfaces so gameplay/Blueprint callers can inspect duplicate-pruning survivors and normalized label-fallback phase detail from one fused row/phase surface instead of joining separate raw-row and normalized-phase arrays themselves
- the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector option owned execution split-phase raw-row / normalized-phase fusion preview surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can inspect duplicate-pruning survivors and normalized label-fallback phase detail from one fused row/phase surface instead of joining separate raw-row and normalized-phase arrays themselves
- the current next bounded packet is to expose one thin generated-mode selector option owned execution split-phase current-selection canonical inspect surface on those same two consumer surfaces so gameplay/Blueprint callers can render just the actively selected option’s fused split-phase normalization state without scanning the broader option array themselves
- 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,90 @@
# HyperTwist Phase 4 gameplay generated-mode selector option owned execution split-phase raw-row / normalized-phase fusion preview surface packet
Created on `2026-05-08`
Status:
- first-party HyperTwist packet
- bounded Phase `4` gameplay-facing consumer slice
## Purpose
This packet closes the next thin gameplay-facing consumer seam above the panel-widget and session-actor generated-mode selector option owned execution split-phase normalization summary preview surface by exposing one parameterized owned execution split-phase raw-row / normalized-phase fusion preview surface for a chosen selector id.
The open tasks were:
- stop forcing gameplay / Blueprint callers to join separate duplicate-pruning raw rows and normalized label-fallback phase arrays just to inspect one chosen option
- expose direct covered-case fused row/phase detail and generated owned-execution fused row/phase detail on the same thin consumer lane
- expose blocked preview posture from that same fused row/phase layer without widening into backend execution behavior
It is not:
- a selector-dispatch behavior change
- a generated-mode launch-request persistence behavior change
- a generated-mode execution deck synthesis change
- a broader gameplay UI composition pass
## Scope
Bounded lane:
- add first-party owned execution split-phase raw-row / normalized-phase fusion preview surfaces in shared training types
- add a coach-library helper that composes the already-landed split-phase normalization summary, label-fallback provenance, and duplicate-pruning provenance surfaces into one fused row/phase layer
- expose that parameterized split-phase fusion preview surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`
- keep the derivation presentation-only and rooted in the already-owned selector/runtime/request surfaces
Out of scope:
- changing selector-choice apply behavior
- changing stored launch-request creation, refresh, or execute behavior
- changing generated-mode execution deck synthesis
- widening into dashboard-only or broader gameplay composition work
## Why this was the right next packet
Before this slice:
- gameplay-facing panel/session consumers already exposed truthful split-phase normalization summary plus the separate raw-definition duplicate-pruning and normalized label-fallback layers for imported selector options
- callers could already inspect those layers separately for a chosen option
But one thin consumer seam was still open:
- callers still had to join separate raw-row and normalized-phase arrays themselves just to render one fused split-phase inspection view for a chosen option
That meant:
- the underlying preview layers were already thin and reusable
- but a common gameplay-facing fused row/phase inspect surface still leaked row-to-phase join work into callers
So the next bounded move was:
- keep the already-landed normalization summary, label-fallback provenance, and duplicate-pruning provenance surfaces unchanged in behavior
- add one narrow fused row/phase surface above them that simply composes those existing layers into a caller-ready inspection view
## What landed
Primary code changes:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewRowSurface`
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewEntrySurface`
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
- added `DeriveCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(...)`
- the fused row/phase preview is composed from the already-landed split-phase normalization summary, label-fallback provenance, and duplicate-pruning provenance surfaces instead of rebuilding normalization behavior
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
- added `GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(const FString& SelectorId)`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
- added `GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionSplitPhaseRawRowNormalizedPhaseFusionPreviewSurface(const FString& SelectorId)`
Consumer result:
- gameplay / Blueprint callers can now inspect duplicate-pruning raw rows and the surviving normalized label-fallback phase detail from one fused row/phase surface for a chosen selector option instead of joining separate raw-row and normalized-phase arrays themselves
## Validation
- full `Development Editor|Win64` solution build for `C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.sln`
- result: `0` warnings, `0` errors