Expose gameplay selector owned-execution provenance preview surface
This commit is contained in:
parent
80fbca56fd
commit
edf106da6c
9 changed files with 1229 additions and 2 deletions
|
|
@ -5654,6 +5654,828 @@ FHyperTwistTrainingCoachPrimaryActionSurface UHyperTwistTrainingCoachLibrary::De
|
|||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
const FHyperTwistTrainingRunState& RunState,
|
||||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
|
||||
OptionLaunchRequestPreviewSurface
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
Surface;
|
||||
Surface.SelectorId = SelectorId;
|
||||
Surface.SelectorLabel = OptionMenuSurface.SelectorLabel;
|
||||
Surface.BindingLabel = OptionMenuSurface.BindingLabel;
|
||||
Surface.Headline =
|
||||
TEXT("Generated Mode Selector Option Owned-Execution Provenance Preview");
|
||||
Surface.bHasSelector = OptionMenuSurface.bHasSelector;
|
||||
|
||||
if (!SelectorId.IsEmpty())
|
||||
{
|
||||
Surface.Headline = OptionMenuSurface.SelectorLabel.IsEmpty()
|
||||
? FString::Printf(
|
||||
TEXT("Generated Mode Selector Option Owned-Execution Provenance Preview: %s"),
|
||||
*SelectorId
|
||||
)
|
||||
: FString::Printf(
|
||||
TEXT("Generated Mode Selector Option Owned-Execution Provenance Preview: %s"),
|
||||
*OptionMenuSurface.SelectorLabel
|
||||
);
|
||||
}
|
||||
|
||||
if (SelectorId.IsEmpty())
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Generated-mode selector option owned-execution provenance preview requires a selector id from the active selector roster.");
|
||||
Surface.CaseSourceSummaryLine = TEXT("Case source attribution: n/a");
|
||||
Surface.DeckSourceSummaryLine = TEXT("Deck source attribution: n/a");
|
||||
Surface.TagSummaryLine = TEXT("Tag posture: n/a");
|
||||
Surface.CurrentSelectionProvenanceLine = TEXT("Current selection: n/a");
|
||||
Surface.DetailLine = OptionLaunchRequestPreviewSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Launch-request preview: n/a")
|
||||
: FString::Printf(
|
||||
TEXT("Launch-request preview: %s"),
|
||||
*OptionLaunchRequestPreviewSurface.StatusLine
|
||||
);
|
||||
return Surface;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingImportedRuntimeSurface& RuntimeSurface =
|
||||
RunState.ActiveDeck.ImportedRuntimeSurface;
|
||||
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest =
|
||||
RunState.ImportedGeneratedModeLaunchRequest;
|
||||
const bool bHasGeneratedModeSurface = RuntimeSurface.IsStructurallyValid()
|
||||
&& RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase);
|
||||
const FHyperTwistTrainingCase* SeedCase = RunState.ActiveDeck.Cases.FindByPredicate(
|
||||
[](const FHyperTwistTrainingCase& Candidate)
|
||||
{
|
||||
return Candidate.IsStructurallyValid();
|
||||
}
|
||||
);
|
||||
|
||||
const auto SanitizeGeneratedModeToken = [](const FString& Value) -> FString
|
||||
{
|
||||
FString Sanitized;
|
||||
Sanitized.Reserve(Value.Len());
|
||||
|
||||
for (const TCHAR Character : Value)
|
||||
{
|
||||
if (FChar::IsAlnum(Character))
|
||||
{
|
||||
Sanitized.AppendChar(FChar::ToLower(Character));
|
||||
}
|
||||
else if (Sanitized.IsEmpty() || Sanitized[Sanitized.Len() - 1] != TEXT('-'))
|
||||
{
|
||||
Sanitized.AppendChar(TEXT('-'));
|
||||
}
|
||||
}
|
||||
|
||||
while (Sanitized.StartsWith(TEXT("-")))
|
||||
{
|
||||
Sanitized.RightChopInline(1, EAllowShrinking::No);
|
||||
}
|
||||
while (Sanitized.EndsWith(TEXT("-")))
|
||||
{
|
||||
Sanitized.LeftChopInline(1, EAllowShrinking::No);
|
||||
}
|
||||
|
||||
return Sanitized.IsEmpty() ? TEXT("value") : Sanitized;
|
||||
};
|
||||
|
||||
const auto DescribeSourceMode = [](const EHyperTwistTrainingSourceMode SourceMode) -> FString
|
||||
{
|
||||
switch (SourceMode)
|
||||
{
|
||||
case EHyperTwistTrainingSourceMode::FirstParty:
|
||||
return TEXT("First Party");
|
||||
case EHyperTwistTrainingSourceMode::DirectDonor:
|
||||
return TEXT("Direct Donor");
|
||||
case EHyperTwistTrainingSourceMode::CleanRoom:
|
||||
return TEXT("Clean Room");
|
||||
case EHyperTwistTrainingSourceMode::Benchmark:
|
||||
return TEXT("Benchmark");
|
||||
default:
|
||||
return TEXT("Unknown");
|
||||
}
|
||||
};
|
||||
|
||||
const auto BuildSourceModeLine = [&DescribeSourceMode](
|
||||
const TCHAR* Prefix,
|
||||
const FHyperTwistTrainingSourceAttribution& Attribution
|
||||
) -> FString
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("%s: %s"),
|
||||
Prefix,
|
||||
*DescribeSourceMode(Attribution.SourceMode)
|
||||
);
|
||||
};
|
||||
|
||||
const auto BuildSourceRefLine = [](
|
||||
const TCHAR* Prefix,
|
||||
const FHyperTwistTrainingSourceAttribution& Attribution
|
||||
) -> FString
|
||||
{
|
||||
TArray<FString> Parts;
|
||||
if (!Attribution.SourceRepo.IsEmpty())
|
||||
{
|
||||
Parts.Add(FString::Printf(TEXT("repo=%s"), *Attribution.SourceRepo));
|
||||
}
|
||||
if (!Attribution.SourceLicense.IsEmpty())
|
||||
{
|
||||
Parts.Add(FString::Printf(TEXT("license=%s"), *Attribution.SourceLicense));
|
||||
}
|
||||
if (!Attribution.SourceTrackId.IsEmpty())
|
||||
{
|
||||
Parts.Add(FString::Printf(TEXT("track=%s"), *Attribution.SourceTrackId));
|
||||
}
|
||||
if (!Attribution.SourceDeckId.IsEmpty())
|
||||
{
|
||||
Parts.Add(FString::Printf(TEXT("deck=%s"), *Attribution.SourceDeckId));
|
||||
}
|
||||
if (!Attribution.SourceCaseId.IsEmpty())
|
||||
{
|
||||
Parts.Add(FString::Printf(TEXT("case=%s"), *Attribution.SourceCaseId));
|
||||
}
|
||||
|
||||
if (Parts.Num() == 0)
|
||||
{
|
||||
return FString::Printf(TEXT("%s: first-party lineage"), Prefix);
|
||||
}
|
||||
|
||||
return FString::Printf(
|
||||
TEXT("%s: %s"),
|
||||
Prefix,
|
||||
*FString::Join(Parts, TEXT(" | "))
|
||||
);
|
||||
};
|
||||
|
||||
const auto BuildSourceNotesLine = [](
|
||||
const TCHAR* Prefix,
|
||||
const FHyperTwistTrainingSourceAttribution& Attribution
|
||||
) -> FString
|
||||
{
|
||||
return FString::Printf(
|
||||
TEXT("%s: %s"),
|
||||
Prefix,
|
||||
Attribution.SourceNotes.IsEmpty() ? TEXT("none") : *Attribution.SourceNotes
|
||||
);
|
||||
};
|
||||
|
||||
const auto BuildTagSummaryLine = [](
|
||||
const TCHAR* Prefix,
|
||||
const TArray<FString>& Tags
|
||||
) -> FString
|
||||
{
|
||||
if (Tags.Num() == 0)
|
||||
{
|
||||
return FString::Printf(TEXT("%s: none"), Prefix);
|
||||
}
|
||||
|
||||
TArray<FString> PreviewTags;
|
||||
const int32 PreviewLimit = FMath::Min(3, Tags.Num());
|
||||
for (int32 Index = 0; Index < PreviewLimit; ++Index)
|
||||
{
|
||||
PreviewTags.Add(Tags[Index]);
|
||||
}
|
||||
|
||||
FString PreviewText = FString::Join(PreviewTags, TEXT(" | "));
|
||||
if (Tags.Num() > PreviewLimit)
|
||||
{
|
||||
PreviewText += FString::Printf(
|
||||
TEXT(" | +%d more"),
|
||||
Tags.Num() - PreviewLimit
|
||||
);
|
||||
}
|
||||
|
||||
return FString::Printf(
|
||||
TEXT("%s: %d [%s]"),
|
||||
Prefix,
|
||||
Tags.Num(),
|
||||
*PreviewText
|
||||
);
|
||||
};
|
||||
|
||||
const auto AppendUniqueTag = [](
|
||||
TArray<FString>& Tags,
|
||||
const FString& Tag
|
||||
)
|
||||
{
|
||||
if (!Tag.IsEmpty())
|
||||
{
|
||||
Tags.AddUnique(Tag);
|
||||
}
|
||||
};
|
||||
|
||||
const auto IncrementSourceModeCounts = [&Surface](
|
||||
const FHyperTwistTrainingSourceAttribution& Attribution,
|
||||
const bool bCaseSource
|
||||
)
|
||||
{
|
||||
switch (Attribution.SourceMode)
|
||||
{
|
||||
case EHyperTwistTrainingSourceMode::FirstParty:
|
||||
if (bCaseSource)
|
||||
{
|
||||
++Surface.FirstPartyCaseSourceOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.FirstPartyDeckSourceOptionCount;
|
||||
}
|
||||
break;
|
||||
case EHyperTwistTrainingSourceMode::DirectDonor:
|
||||
if (bCaseSource)
|
||||
{
|
||||
++Surface.DirectDonorCaseSourceOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.DirectDonorDeckSourceOptionCount;
|
||||
}
|
||||
break;
|
||||
case EHyperTwistTrainingSourceMode::CleanRoom:
|
||||
if (bCaseSource)
|
||||
{
|
||||
++Surface.CleanRoomCaseSourceOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.CleanRoomDeckSourceOptionCount;
|
||||
}
|
||||
break;
|
||||
case EHyperTwistTrainingSourceMode::Benchmark:
|
||||
if (bCaseSource)
|
||||
{
|
||||
++Surface.BenchmarkCaseSourceOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.BenchmarkDeckSourceOptionCount;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (!RunState.IsStructurallyValid() || !bHasGeneratedModeSurface)
|
||||
{
|
||||
Surface.StatusLine = OptionMenuSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Generated-mode selector option owned-execution provenance preview is not currently available.")
|
||||
: OptionMenuSurface.StatusLine;
|
||||
Surface.CaseSourceSummaryLine = TEXT("Case source attribution: n/a");
|
||||
Surface.DeckSourceSummaryLine = TEXT("Deck source attribution: n/a");
|
||||
Surface.TagSummaryLine = TEXT("Tag posture: n/a");
|
||||
Surface.CurrentSelectionProvenanceLine = OptionMenuSurface.bHasUnresolvedSelectionDetail
|
||||
? OptionMenuSurface.UnresolvedSelectionLine
|
||||
: (OptionMenuSurface.bHasSelection
|
||||
? TEXT("Current selection remains cached, but no active owned-execution provenance preview is available.")
|
||||
: TEXT("Current selection: unresolved"));
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Launch-request preview: %s"),
|
||||
OptionLaunchRequestPreviewSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *OptionLaunchRequestPreviewSurface.StatusLine
|
||||
);
|
||||
return Surface;
|
||||
}
|
||||
|
||||
for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewEntrySurface&
|
||||
PreviewEntry : OptionLaunchRequestPreviewSurface.OptionEntries)
|
||||
{
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewEntrySurface
|
||||
Entry;
|
||||
Entry.OptionId = PreviewEntry.OptionId;
|
||||
Entry.Label = PreviewEntry.Label;
|
||||
Entry.OptionValue = PreviewEntry.OptionValue;
|
||||
Entry.LaunchRequestPreviewKind = PreviewEntry.LaunchRequestPreviewKind;
|
||||
Entry.bMatchesCurrentSelection = PreviewEntry.bMatchesCurrentSelection;
|
||||
Entry.bStartsOwnedCaseImmediately = PreviewEntry.bStartsOwnedCaseImmediately;
|
||||
|
||||
switch (PreviewEntry.LaunchRequestPreviewKind)
|
||||
{
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
DirectOwnedCaseStart:
|
||||
{
|
||||
FHyperTwistTrainingCase MatchingCase;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorOptionCaseFromDeck(
|
||||
RunState.ActiveDeck,
|
||||
SelectorId,
|
||||
PreviewEntry.OptionId,
|
||||
MatchingCase))
|
||||
{
|
||||
Entry.PreviewCaseSourceAttribution = MatchingCase.SourceAttribution;
|
||||
Entry.PreviewDeckSourceAttribution = RunState.ActiveDeck.SourceAttribution;
|
||||
Entry.PreviewCaseSourceModeLabel = DescribeSourceMode(
|
||||
Entry.PreviewCaseSourceAttribution.SourceMode
|
||||
);
|
||||
Entry.PreviewDeckSourceModeLabel = DescribeSourceMode(
|
||||
Entry.PreviewDeckSourceAttribution.SourceMode
|
||||
);
|
||||
Entry.PreviewCaseTags = MatchingCase.Tags;
|
||||
Entry.PreviewDeckTags = RunState.ActiveDeck.Tags;
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewDeckTags,
|
||||
TEXT("runtime-surface:selector-option-applied")
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewDeckTags,
|
||||
FString::Printf(TEXT("selector:%s"), *SelectorId.ToLower())
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewDeckTags,
|
||||
FString::Printf(TEXT("selector-option:%s"), *PreviewEntry.OptionId.ToLower())
|
||||
);
|
||||
|
||||
Entry.bHasCaseSourceAttribution =
|
||||
Entry.PreviewCaseSourceAttribution.IsStructurallyValid();
|
||||
Entry.bHasDeckSourceAttribution =
|
||||
Entry.PreviewDeckSourceAttribution.IsStructurallyValid();
|
||||
Entry.CaseTagCount = Entry.PreviewCaseTags.Num();
|
||||
Entry.DeckTagCount = Entry.PreviewDeckTags.Num();
|
||||
Entry.bHasCaseTags = Entry.CaseTagCount > 0;
|
||||
Entry.bHasDeckTags = Entry.DeckTagCount > 0;
|
||||
Entry.CaseSourceModeLine = BuildSourceModeLine(
|
||||
TEXT("Case source mode"),
|
||||
Entry.PreviewCaseSourceAttribution
|
||||
);
|
||||
Entry.CaseSourceRefLine = BuildSourceRefLine(
|
||||
TEXT("Case source ref"),
|
||||
Entry.PreviewCaseSourceAttribution
|
||||
);
|
||||
Entry.CaseSourceNotesLine = BuildSourceNotesLine(
|
||||
TEXT("Case source notes"),
|
||||
Entry.PreviewCaseSourceAttribution
|
||||
);
|
||||
Entry.DeckSourceModeLine = BuildSourceModeLine(
|
||||
TEXT("Deck source mode"),
|
||||
Entry.PreviewDeckSourceAttribution
|
||||
);
|
||||
Entry.DeckSourceRefLine = BuildSourceRefLine(
|
||||
TEXT("Deck source ref"),
|
||||
Entry.PreviewDeckSourceAttribution
|
||||
);
|
||||
Entry.DeckSourceNotesLine = BuildSourceNotesLine(
|
||||
TEXT("Deck source notes"),
|
||||
Entry.PreviewDeckSourceAttribution
|
||||
);
|
||||
Entry.CaseTagSummaryLine = BuildTagSummaryLine(
|
||||
TEXT("Case tags on execute"),
|
||||
Entry.PreviewCaseTags
|
||||
);
|
||||
Entry.DeckTagSummaryLine = BuildTagSummaryLine(
|
||||
TEXT("Deck tags on execute"),
|
||||
Entry.PreviewDeckTags
|
||||
);
|
||||
Entry.ProvenanceSourceLine =
|
||||
TEXT("Provenance source: exact direct covered-case attribution from the resolved imported option case plus active deck lineage.");
|
||||
Entry.PreviewStabilityLine =
|
||||
TEXT("Preview stability: exact direct owned-case provenance preview from covered-case launch.");
|
||||
Entry.bHasExactProvenancePreview = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.DirectExactOptionCount;
|
||||
IncrementSourceModeCounts(Entry.PreviewCaseSourceAttribution, true);
|
||||
IncrementSourceModeCounts(Entry.PreviewDeckSourceAttribution, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entry.CaseSourceModeLine = TEXT("Case source mode: unavailable");
|
||||
Entry.CaseSourceRefLine = TEXT("Case source ref: unavailable");
|
||||
Entry.CaseSourceNotesLine = TEXT("Case source notes: unavailable");
|
||||
Entry.DeckSourceModeLine = TEXT("Deck source mode: unavailable");
|
||||
Entry.DeckSourceRefLine = TEXT("Deck source ref: unavailable");
|
||||
Entry.DeckSourceNotesLine = TEXT("Deck source notes: unavailable");
|
||||
Entry.CaseTagSummaryLine = TEXT("Case tags on execute: unavailable");
|
||||
Entry.DeckTagSummaryLine = TEXT("Deck tags on execute: unavailable");
|
||||
Entry.ProvenanceSourceLine =
|
||||
TEXT("Provenance source: unavailable because the covered case could not be re-resolved from the active deck.");
|
||||
Entry.PreviewStabilityLine = TEXT("Preview stability: unavailable");
|
||||
Entry.bCanPreview = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
StoredRequestReusable:
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
RefreshRequired:
|
||||
{
|
||||
if (SeedCase == nullptr)
|
||||
{
|
||||
Entry.CaseSourceModeLine = TEXT("Case source mode: unavailable");
|
||||
Entry.CaseSourceRefLine = TEXT("Case source ref: unavailable");
|
||||
Entry.CaseSourceNotesLine = TEXT("Case source notes: unavailable");
|
||||
Entry.DeckSourceModeLine = TEXT("Deck source mode: unavailable");
|
||||
Entry.DeckSourceRefLine = TEXT("Deck source ref: unavailable");
|
||||
Entry.DeckSourceNotesLine = TEXT("Deck source notes: unavailable");
|
||||
Entry.CaseTagSummaryLine = TEXT("Case tags on execute: unavailable");
|
||||
Entry.DeckTagSummaryLine = TEXT("Deck tags on execute: unavailable");
|
||||
Entry.ProvenanceSourceLine =
|
||||
TEXT("Provenance source: unavailable because the active generated-mode surface has no structurally valid seed case.");
|
||||
Entry.PreviewStabilityLine = TEXT("Preview stability: unavailable");
|
||||
Entry.bCanPreview = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool bStoredRequestReusable =
|
||||
PreviewEntry.LaunchRequestPreviewKind
|
||||
== EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
StoredRequestReusable;
|
||||
const bool bHasExactRequestId =
|
||||
bStoredRequestReusable && LaunchRequest.IsStructurallyValid()
|
||||
&& !LaunchRequest.RequestId.IsEmpty();
|
||||
const FString PreviewRequestId = bHasExactRequestId
|
||||
? LaunchRequest.RequestId
|
||||
: FString(TEXT("<next-request-id>"));
|
||||
const FString PreviewRequestTagToken = bHasExactRequestId
|
||||
? SanitizeGeneratedModeToken(PreviewRequestId)
|
||||
: FString(TEXT("<next-request-id>"));
|
||||
const FString PreviewSurfaceToken = PreviewEntry.HypotheticalSurfaceId.IsEmpty()
|
||||
? SanitizeGeneratedModeToken(RuntimeSurface.SurfaceId)
|
||||
: SanitizeGeneratedModeToken(PreviewEntry.HypotheticalSurfaceId);
|
||||
const FString CaseExecutionNote = FString::Printf(
|
||||
TEXT("Owned generated-mode execution case produced from request %s."),
|
||||
*PreviewRequestId
|
||||
);
|
||||
const FString DeckExecutionNote = FString::Printf(
|
||||
TEXT("Owned generated-mode execution deck produced from request %s."),
|
||||
*PreviewRequestId
|
||||
);
|
||||
|
||||
Entry.PreviewCaseSourceAttribution =
|
||||
SeedCase->SourceAttribution.IsStructurallyValid()
|
||||
? SeedCase->SourceAttribution
|
||||
: RunState.ActiveDeck.SourceAttribution;
|
||||
if (Entry.PreviewCaseSourceAttribution.SourceCaseId.IsEmpty())
|
||||
{
|
||||
Entry.PreviewCaseSourceAttribution.SourceCaseId = SeedCase->CaseId;
|
||||
}
|
||||
Entry.PreviewCaseSourceAttribution.SourceNotes =
|
||||
Entry.PreviewCaseSourceAttribution.SourceNotes.IsEmpty()
|
||||
? CaseExecutionNote
|
||||
: FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*Entry.PreviewCaseSourceAttribution.SourceNotes,
|
||||
*CaseExecutionNote
|
||||
);
|
||||
Entry.PreviewDeckSourceAttribution = RunState.ActiveDeck.SourceAttribution;
|
||||
Entry.PreviewDeckSourceAttribution.SourceNotes =
|
||||
Entry.PreviewDeckSourceAttribution.SourceNotes.IsEmpty()
|
||||
? DeckExecutionNote
|
||||
: FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*Entry.PreviewDeckSourceAttribution.SourceNotes,
|
||||
*DeckExecutionNote
|
||||
);
|
||||
Entry.PreviewCaseSourceModeLabel = DescribeSourceMode(
|
||||
Entry.PreviewCaseSourceAttribution.SourceMode
|
||||
);
|
||||
Entry.PreviewDeckSourceModeLabel = DescribeSourceMode(
|
||||
Entry.PreviewDeckSourceAttribution.SourceMode
|
||||
);
|
||||
Entry.PreviewCaseTags = SeedCase->Tags;
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewCaseTags,
|
||||
TEXT("runtime-surface:generated-mode")
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewCaseTags,
|
||||
TEXT("generated-mode:owned-execution")
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewCaseTags,
|
||||
FString::Printf(
|
||||
TEXT("generated-request:%s"),
|
||||
*PreviewRequestTagToken
|
||||
)
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewCaseTags,
|
||||
FString::Printf(
|
||||
TEXT("generated-surface:%s"),
|
||||
*PreviewSurfaceToken
|
||||
)
|
||||
);
|
||||
for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestSelectorChoiceEntrySurface&
|
||||
ChoiceEntry : PreviewEntry.SelectorChoiceEntries)
|
||||
{
|
||||
if (!ChoiceEntry.bHasChoice || ChoiceEntry.SelectorId.IsEmpty()
|
||||
|| ChoiceEntry.SelectedValue.IsEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewCaseTags,
|
||||
FString::Printf(
|
||||
TEXT("generated-selector:%s=%s"),
|
||||
*SanitizeGeneratedModeToken(ChoiceEntry.SelectorId),
|
||||
*SanitizeGeneratedModeToken(ChoiceEntry.SelectedValue)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Entry.PreviewDeckTags = RunState.ActiveDeck.Tags;
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewDeckTags,
|
||||
TEXT("runtime-surface:generated-mode")
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewDeckTags,
|
||||
TEXT("generated-mode:owned-execution")
|
||||
);
|
||||
AppendUniqueTag(
|
||||
Entry.PreviewDeckTags,
|
||||
FString::Printf(
|
||||
TEXT("generated-request:%s"),
|
||||
*PreviewRequestTagToken
|
||||
)
|
||||
);
|
||||
|
||||
Entry.bHasCaseSourceAttribution =
|
||||
Entry.PreviewCaseSourceAttribution.IsStructurallyValid();
|
||||
Entry.bHasDeckSourceAttribution =
|
||||
Entry.PreviewDeckSourceAttribution.IsStructurallyValid();
|
||||
Entry.CaseTagCount = Entry.PreviewCaseTags.Num();
|
||||
Entry.DeckTagCount = Entry.PreviewDeckTags.Num();
|
||||
Entry.bHasCaseTags = Entry.CaseTagCount > 0;
|
||||
Entry.bHasDeckTags = Entry.DeckTagCount > 0;
|
||||
Entry.CaseSourceModeLine = BuildSourceModeLine(
|
||||
TEXT("Case source mode"),
|
||||
Entry.PreviewCaseSourceAttribution
|
||||
);
|
||||
Entry.CaseSourceRefLine = BuildSourceRefLine(
|
||||
TEXT("Case source ref"),
|
||||
Entry.PreviewCaseSourceAttribution
|
||||
);
|
||||
Entry.CaseSourceNotesLine = BuildSourceNotesLine(
|
||||
TEXT("Case source notes"),
|
||||
Entry.PreviewCaseSourceAttribution
|
||||
);
|
||||
Entry.DeckSourceModeLine = BuildSourceModeLine(
|
||||
TEXT("Deck source mode"),
|
||||
Entry.PreviewDeckSourceAttribution
|
||||
);
|
||||
Entry.DeckSourceRefLine = BuildSourceRefLine(
|
||||
TEXT("Deck source ref"),
|
||||
Entry.PreviewDeckSourceAttribution
|
||||
);
|
||||
Entry.DeckSourceNotesLine = BuildSourceNotesLine(
|
||||
TEXT("Deck source notes"),
|
||||
Entry.PreviewDeckSourceAttribution
|
||||
);
|
||||
Entry.CaseTagSummaryLine = BuildTagSummaryLine(
|
||||
TEXT("Case tags on execute"),
|
||||
Entry.PreviewCaseTags
|
||||
);
|
||||
Entry.DeckTagSummaryLine = BuildTagSummaryLine(
|
||||
TEXT("Deck tags on execute"),
|
||||
Entry.PreviewDeckTags
|
||||
);
|
||||
Entry.ProvenanceSourceLine =
|
||||
bHasExactRequestId
|
||||
? TEXT("Provenance source: generated owned-execution attribution and tags synthesized exactly from the seed case, active deck lineage, and reusable stored request.")
|
||||
: TEXT("Provenance source: generated owned-execution attribution is exact, but request-id-dependent notes and tags remain preview templates until execute refreshes the launch request.");
|
||||
Entry.PreviewStabilityLine =
|
||||
bHasExactRequestId
|
||||
? TEXT("Preview stability: exact while execute reuses the current stored request.")
|
||||
: TEXT("Preview stability: case/deck attribution is exact, but request-id-specific notes and tags remain template preview until launch-request refresh.");
|
||||
Entry.bHasExactProvenancePreview = bHasExactRequestId;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.GeneratedExactOptionCount;
|
||||
IncrementSourceModeCounts(Entry.PreviewCaseSourceAttribution, true);
|
||||
IncrementSourceModeCounts(Entry.PreviewDeckSourceAttribution, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
UnresolvedAfterChoice:
|
||||
Entry.CaseSourceModeLine =
|
||||
TEXT("Case source mode: blocked until every required selector is resolved.");
|
||||
Entry.CaseSourceRefLine =
|
||||
TEXT("Case source ref: blocked until every required selector is resolved.");
|
||||
Entry.CaseSourceNotesLine =
|
||||
TEXT("Case source notes: blocked until every required selector is resolved.");
|
||||
Entry.DeckSourceModeLine =
|
||||
TEXT("Deck source mode: blocked until every required selector is resolved.");
|
||||
Entry.DeckSourceRefLine =
|
||||
TEXT("Deck source ref: blocked until every required selector is resolved.");
|
||||
Entry.DeckSourceNotesLine =
|
||||
TEXT("Deck source notes: blocked until every required selector is resolved.");
|
||||
Entry.CaseTagSummaryLine =
|
||||
TEXT("Case tags on execute: blocked until every required selector is resolved.");
|
||||
Entry.DeckTagSummaryLine =
|
||||
TEXT("Deck tags on execute: blocked until every required selector is resolved.");
|
||||
Entry.ProvenanceSourceLine =
|
||||
TEXT("Provenance source: blocked while selector coverage remains incomplete.");
|
||||
Entry.PreviewStabilityLine =
|
||||
TEXT("Preview stability: blocked while selector coverage remains incomplete.");
|
||||
Entry.bPreviewBlocked = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.BlockedOptionCount;
|
||||
break;
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
PayloadUnavailable:
|
||||
Entry.CaseSourceModeLine =
|
||||
TEXT("Case source mode: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.CaseSourceRefLine =
|
||||
TEXT("Case source ref: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.CaseSourceNotesLine =
|
||||
TEXT("Case source notes: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.DeckSourceModeLine =
|
||||
TEXT("Deck source mode: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.DeckSourceRefLine =
|
||||
TEXT("Deck source ref: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.DeckSourceNotesLine =
|
||||
TEXT("Deck source notes: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.CaseTagSummaryLine =
|
||||
TEXT("Case tags on execute: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.DeckTagSummaryLine =
|
||||
TEXT("Deck tags on execute: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.ProvenanceSourceLine =
|
||||
TEXT("Provenance source: blocked while the hypothetical generated-mode payload remains structurally invalid.");
|
||||
Entry.PreviewStabilityLine =
|
||||
TEXT("Preview stability: blocked while the hypothetical generated-mode payload remains structurally invalid.");
|
||||
Entry.bPreviewBlocked = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.BlockedOptionCount;
|
||||
break;
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::Unavailable:
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None:
|
||||
default:
|
||||
Entry.CaseSourceModeLine = TEXT("Case source mode: unavailable");
|
||||
Entry.CaseSourceRefLine = TEXT("Case source ref: unavailable");
|
||||
Entry.CaseSourceNotesLine = TEXT("Case source notes: unavailable");
|
||||
Entry.DeckSourceModeLine = TEXT("Deck source mode: unavailable");
|
||||
Entry.DeckSourceRefLine = TEXT("Deck source ref: unavailable");
|
||||
Entry.DeckSourceNotesLine = TEXT("Deck source notes: unavailable");
|
||||
Entry.CaseTagSummaryLine = TEXT("Case tags on execute: unavailable");
|
||||
Entry.DeckTagSummaryLine = TEXT("Deck tags on execute: unavailable");
|
||||
Entry.ProvenanceSourceLine = TEXT("Provenance source: unavailable");
|
||||
Entry.PreviewStabilityLine = TEXT("Preview stability: unavailable");
|
||||
Entry.bCanPreview = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Entry.bHasCaseTags)
|
||||
{
|
||||
++Surface.CaseTaggedOptionCount;
|
||||
}
|
||||
if (Entry.bHasDeckTags)
|
||||
{
|
||||
++Surface.DeckTaggedOptionCount;
|
||||
}
|
||||
if (Entry.PreviewCaseTags.Contains(TEXT("generated-mode:owned-execution")))
|
||||
{
|
||||
++Surface.GeneratedExecutionCaseTagOptionCount;
|
||||
}
|
||||
if (Entry.PreviewDeckTags.Contains(TEXT("generated-mode:owned-execution")))
|
||||
{
|
||||
++Surface.GeneratedExecutionDeckTagOptionCount;
|
||||
}
|
||||
|
||||
Entry.DetailLine = PreviewEntry.DetailLine.IsEmpty()
|
||||
? Entry.PreviewStabilityLine
|
||||
: FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*Entry.PreviewStabilityLine,
|
||||
*PreviewEntry.DetailLine
|
||||
);
|
||||
|
||||
if (Entry.bMatchesCurrentSelection)
|
||||
{
|
||||
Surface.bCurrentSelectionHasExactProvenancePreview =
|
||||
Entry.bHasExactProvenancePreview;
|
||||
Surface.bCurrentSelectionHasCaseSourceAttribution =
|
||||
Entry.bHasCaseSourceAttribution;
|
||||
Surface.bCurrentSelectionHasDeckSourceAttribution =
|
||||
Entry.bHasDeckSourceAttribution;
|
||||
Surface.bCurrentSelectionHasCaseTags = Entry.bHasCaseTags;
|
||||
Surface.bCurrentSelectionHasDeckTags = Entry.bHasDeckTags;
|
||||
Surface.CurrentSelectionProvenanceLine = FString::Printf(
|
||||
TEXT("Current selection: case %s | deck %s | case tags %d | deck tags %d | %s"),
|
||||
Entry.PreviewCaseSourceModeLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *Entry.PreviewCaseSourceModeLabel,
|
||||
Entry.PreviewDeckSourceModeLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *Entry.PreviewDeckSourceModeLabel,
|
||||
Entry.CaseTagCount,
|
||||
Entry.DeckTagCount,
|
||||
*Entry.PreviewStabilityLine
|
||||
);
|
||||
}
|
||||
|
||||
Surface.OptionEntries.Add(MoveTemp(Entry));
|
||||
}
|
||||
|
||||
Surface.bHasOwnedExecutionProvenancePreviewOptions = Surface.OptionEntries.Num() > 0;
|
||||
Surface.bHasDirectProvenancePreviewOptions = Surface.DirectExactOptionCount > 0;
|
||||
Surface.bHasGeneratedProvenancePreviewOptions = Surface.GeneratedExactOptionCount > 0;
|
||||
Surface.bHasBlockedProvenancePreviewOptions = Surface.BlockedOptionCount > 0;
|
||||
|
||||
Surface.CaseSourceSummaryLine = Surface.OptionEntries.Num() > 0
|
||||
? FString::Printf(
|
||||
TEXT("Case source attribution: %d first-party | %d direct donor | %d clean-room | %d benchmark"),
|
||||
Surface.FirstPartyCaseSourceOptionCount,
|
||||
Surface.DirectDonorCaseSourceOptionCount,
|
||||
Surface.CleanRoomCaseSourceOptionCount,
|
||||
Surface.BenchmarkCaseSourceOptionCount
|
||||
)
|
||||
: TEXT("Case source attribution: no imported options");
|
||||
Surface.DeckSourceSummaryLine = Surface.OptionEntries.Num() > 0
|
||||
? FString::Printf(
|
||||
TEXT("Deck source attribution: %d first-party | %d direct donor | %d clean-room | %d benchmark"),
|
||||
Surface.FirstPartyDeckSourceOptionCount,
|
||||
Surface.DirectDonorDeckSourceOptionCount,
|
||||
Surface.CleanRoomDeckSourceOptionCount,
|
||||
Surface.BenchmarkDeckSourceOptionCount
|
||||
)
|
||||
: TEXT("Deck source attribution: no imported options");
|
||||
Surface.TagSummaryLine = Surface.OptionEntries.Num() > 0
|
||||
? FString::Printf(
|
||||
TEXT("Tag posture: %d case-tagged | %d deck-tagged | %d generated-case-tagged | %d generated-deck-tagged"),
|
||||
Surface.CaseTaggedOptionCount,
|
||||
Surface.DeckTaggedOptionCount,
|
||||
Surface.GeneratedExecutionCaseTagOptionCount,
|
||||
Surface.GeneratedExecutionDeckTagOptionCount
|
||||
)
|
||||
: TEXT("Tag posture: no imported options");
|
||||
|
||||
if (Surface.CurrentSelectionProvenanceLine.IsEmpty())
|
||||
{
|
||||
if (OptionMenuSurface.bHasUnresolvedSelectionDetail)
|
||||
{
|
||||
Surface.CurrentSelectionProvenanceLine =
|
||||
OptionMenuSurface.UnresolvedSelectionLine;
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelection)
|
||||
{
|
||||
Surface.CurrentSelectionProvenanceLine =
|
||||
TEXT("Current selection has no additional owned-execution provenance preview.");
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Surface.CurrentSelectionProvenanceLine = TEXT("Current selection: unresolved");
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.CurrentSelectionProvenanceLine = TEXT("Current selection: n/a");
|
||||
}
|
||||
}
|
||||
|
||||
if (OptionMenuSurface.bHasSelector && Surface.OptionEntries.Num() > 0)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Generated-mode selector option owned-execution provenance preview exposes %d direct exact option%s, %d generated preview option%s, %d blocked option%s, and %d unavailable option%s."),
|
||||
Surface.DirectExactOptionCount,
|
||||
Surface.DirectExactOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.GeneratedExactOptionCount,
|
||||
Surface.GeneratedExactOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.BlockedOptionCount,
|
||||
Surface.BlockedOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.UnavailableOptionCount,
|
||||
Surface.UnavailableOptionCount == 1 ? TEXT("") : TEXT("s")
|
||||
);
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Generated-mode selector option owned-execution provenance preview is active, but this selector does not expose imported options.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine = OptionMenuSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Generated-mode selector option owned-execution provenance preview is not currently available.")
|
||||
: OptionMenuSurface.StatusLine;
|
||||
}
|
||||
|
||||
const FString SelectorSummary = Surface.SelectorLabel.IsEmpty()
|
||||
? (Surface.SelectorId.IsEmpty() ? FString(TEXT("n/a")) : Surface.SelectorId)
|
||||
: Surface.SelectorLabel;
|
||||
const FString BindingSummary = Surface.BindingLabel.IsEmpty()
|
||||
? FString(TEXT("n/a"))
|
||||
: Surface.BindingLabel;
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Launch-request preview: %s | Selector: %s | Binding: %s"),
|
||||
OptionLaunchRequestPreviewSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *OptionLaunchRequestPreviewSurface.StatusLine,
|
||||
*SelectorSummary,
|
||||
*BindingSummary
|
||||
);
|
||||
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachQueueControlSurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachQueueControlSurface(
|
||||
const FHyperTwistTrainingCoachSessionQueueState& QueueState,
|
||||
|
|
|
|||
|
|
@ -948,6 +948,25 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwne
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const
|
||||
{
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface
|
||||
OptionLaunchRequestPreviewSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId);
|
||||
return UHyperTwistTrainingCoachLibrary::
|
||||
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
CachedRunState,
|
||||
SelectorId,
|
||||
OptionMenuSurface,
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
|
||||
const int32 MaxCases,
|
||||
const FString& StartActionSourceLabel
|
||||
|
|
|
|||
|
|
@ -929,6 +929,25 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwn
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const
|
||||
{
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface
|
||||
OptionLaunchRequestPreviewSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId);
|
||||
return UHyperTwistTrainingCoachLibrary::
|
||||
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
CachedRunState,
|
||||
SelectorId,
|
||||
OptionMenuSurface,
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
|
||||
const int32 MaxCases
|
||||
)
|
||||
|
|
|
|||
|
|
@ -817,4 +817,14 @@ public:
|
|||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
const FHyperTwistTrainingRunState& RunState,
|
||||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -320,6 +320,12 @@ public:
|
|||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedRun(
|
||||
int32 MaxCases,
|
||||
|
|
|
|||
|
|
@ -301,6 +301,12 @@ public:
|
|||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);
|
||||
|
||||
|
|
|
|||
|
|
@ -10882,3 +10882,246 @@ struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSu
|
|||
|| bHasOwnedExecutionPuzzleSubsetDifficultyPreviewOptions;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewEntrySurface
|
||||
{
|
||||
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 CaseSourceModeLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseSourceRefLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseSourceNotesLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckSourceModeLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckSourceRefLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckSourceNotesLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseTagSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckTagSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ProvenanceSourceLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewStabilityLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingSourceAttribution PreviewCaseSourceAttribution;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingSourceAttribution PreviewDeckSourceAttribution;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewCaseSourceModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewDeckSourceModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> PreviewCaseTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> PreviewDeckTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CaseTagCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DeckTagCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bMatchesCurrentSelection = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bStartsOwnedCaseImmediately = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasExactProvenancePreview = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasCaseSourceAttribution = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDeckSourceAttribution = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasCaseTags = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDeckTags = 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()
|
||||
|| !CaseSourceModeLine.IsEmpty()
|
||||
|| !DeckSourceModeLine.IsEmpty()
|
||||
|| !CaseTagSummaryLine.IsEmpty()
|
||||
|| !DeckTagSummaryLine.IsEmpty()
|
||||
|| LaunchRequestPreviewKind
|
||||
!= EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None
|
||||
|| bCanPreview;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface
|
||||
{
|
||||
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 CaseSourceSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeckSourceSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TagSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CurrentSelectionProvenanceLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewEntrySurface>
|
||||
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 FirstPartyCaseSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DirectDonorCaseSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CleanRoomCaseSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BenchmarkCaseSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FirstPartyDeckSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DirectDonorDeckSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CleanRoomDeckSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BenchmarkDeckSourceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CaseTaggedOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DeckTaggedOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 GeneratedExecutionCaseTagOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 GeneratedExecutionDeckTagOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasSelector = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasOwnedExecutionProvenancePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDirectProvenancePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasGeneratedProvenancePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasBlockedProvenancePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasExactProvenancePreview = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasCaseSourceAttribution = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasDeckSourceAttribution = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasCaseTags = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasDeckTags = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !SelectorId.IsEmpty()
|
||||
|| OptionEntries.Num() > 0
|
||||
|| bHasSelector
|
||||
|| bHasOwnedExecutionProvenancePreviewOptions;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 puzzle-id / subset-id / difficulty preview surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can render exact direct-case scope and exact generated owned execution puzzle, subset, and difficulty posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- the current next bounded packet is to expose one thin generated-mode selector option owned execution source-attribution / tag provenance preview surface on those same two consumer surfaces so gameplay/Blueprint callers can render the resulting owned execution provenance and tag posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- 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 source-attribution / tag provenance preview surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can render resulting case/deck attribution plus exact-or-template tag posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- the current next bounded packet is to expose one thin generated-mode selector option owned execution deck-title / selection-policy preview surface on those same two consumer surfaces so gameplay/Blueprint callers can render resulting owned execution container identity and selection-policy posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
# HyperTwist Phase 4 gameplay generated-mode selector option owned execution source-attribution / tag provenance 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 puzzle-id / subset-id / difficulty preview surface by exposing one parameterized owned execution provenance preview surface for a chosen selector id.
|
||||
|
||||
The open tasks were:
|
||||
|
||||
- stop forcing gameplay / Blueprint callers to rebuild generated deck attribution rules and tag synthesis just to explain where a chosen imported option would execute from
|
||||
- expose direct covered-case case/deck attribution plus generated owned-execution case/deck attribution on the same thin consumer lane
|
||||
- expose resulting case and deck tag posture, including generated request/surface/selector tags, 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 provenance preview surfaces in shared training types
|
||||
- add a coach-library helper that projects case/deck source attribution and tag posture over the already-landed launch-request preview surface plus active run state
|
||||
- expose that parameterized provenance 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 owned case identity, prompt presentation, delivery mode, reveal posture, target time, and execution scope preview for imported selector options
|
||||
- callers could tell what owned execution would run
|
||||
|
||||
But one thin consumer seam was still open:
|
||||
|
||||
- callers still had to reconstruct source attribution and generated tag posture from direct covered-case fields, active deck state, stored request state, and generated owned-execution synthesis rules if they wanted to explain where that execution came from
|
||||
|
||||
That meant:
|
||||
|
||||
- execution preview was already thin and reusable
|
||||
- but provenance and tag posture still leaked generated deck composition rules into callers
|
||||
|
||||
So the next bounded move was:
|
||||
|
||||
- keep the already-landed owned execution scope preview surface unchanged in behavior
|
||||
- reuse the already-cached launch-request preview surface and active run state to expose one narrow owned execution provenance surface above it
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
|
||||
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewEntrySurface`
|
||||
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
|
||||
- added `DeriveCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(...)`
|
||||
- provenance preview is derived from cached run state plus the already-landed launch-request preview surface
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
|
||||
- added `GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(const FString& SelectorId)`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
|
||||
- added `GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionProvenancePreviewSurface(const FString& SelectorId)`
|
||||
|
||||
Surface behavior:
|
||||
|
||||
- reports exact direct covered-case case/deck attribution and direct execution tag posture for selector options that dispatch straight to owned cases
|
||||
- reports generated owned-execution case/deck attribution and generated execution tag posture for previewable generated-mode options
|
||||
- keeps reusable stored-request cases exact, while marking refresh-required cases as attribution-exact but request-id-dependent note/tag templates until execute refreshes the launch request
|
||||
- keeps unresolved or payload-invalid choices inspectable as blocked provenance-preview states instead of collapsing them into a generic unavailable branch
|
||||
- keeps the surface presentation-only and compatible with the already-landed launch / execution, request-alignment, stored-request delta, launch-request payload / refresh-preview, launch-request metadata / origin-notes preview, launch-request envelope / request-source preview, owned execution case / canonical-state preview, owned execution prompt preview, owned execution delivery preview, and owned execution scope preview surfaces
|
||||
|
||||
## Validation
|
||||
|
||||
Validation target:
|
||||
|
||||
- full `Development Editor|Win64` build of `C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.sln`
|
||||
|
||||
Result:
|
||||
|
||||
- passed with `0` warnings and `0` errors
|
||||
|
||||
## Follow-on
|
||||
|
||||
The next bounded packet on this same gameplay-facing consumer lane should stay thin and expose one generated-mode selector option owned execution deck-title / selection-policy preview surface so callers can render resulting owned execution container identity and selection-policy posture for a chosen option without rebuilding generated deck composition rules directly.
|
||||
Loading…
Add table
Reference in a new issue