Expose gameplay readiness eligibility surface
This commit is contained in:
parent
6db9557751
commit
eec693883d
9 changed files with 550 additions and 2 deletions
|
|
@ -324,6 +324,29 @@ namespace HyperTwistTrainingCoachLibraryInternal
|
|||
}
|
||||
}
|
||||
|
||||
FString DescribeCoachEligibilityKind(
|
||||
const EHyperTwistTrainingCoachEligibilityKind EligibilityKind
|
||||
)
|
||||
{
|
||||
switch (EligibilityKind)
|
||||
{
|
||||
case EHyperTwistTrainingCoachEligibilityKind::PrimaryAction:
|
||||
return TEXT("primary coach continuation");
|
||||
case EHyperTwistTrainingCoachEligibilityKind::Promote:
|
||||
return TEXT("deferred promotion");
|
||||
case EHyperTwistTrainingCoachEligibilityKind::Defer:
|
||||
return TEXT("defer control");
|
||||
case EHyperTwistTrainingCoachEligibilityKind::ActiveRunBlocked:
|
||||
return TEXT("active-run block");
|
||||
case EHyperTwistTrainingCoachEligibilityKind::QueueSuppressed:
|
||||
return TEXT("queue suppression");
|
||||
case EHyperTwistTrainingCoachEligibilityKind::NoEligibleAction:
|
||||
return TEXT("no eligible action");
|
||||
default:
|
||||
return TEXT("none");
|
||||
}
|
||||
}
|
||||
|
||||
FString DescribeCoachQueuePostureKind(
|
||||
const EHyperTwistTrainingCoachQueuePostureKind PostureKind)
|
||||
{
|
||||
|
|
@ -6301,3 +6324,220 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachWorkloadBudgetSurface(
|
|||
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachReadinessEligibilitySurface(
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState,
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface& PrimaryActionSurface,
|
||||
const FHyperTwistTrainingCoachQueueControlSurface& QueueControlSurface,
|
||||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface& QueueRecoveryPostureSurface,
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface& HandoffContinuationSurface,
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface& FocusProvenanceSurface,
|
||||
const FHyperTwistTrainingCoachWorkloadBudgetSurface& WorkloadBudgetSurface
|
||||
)
|
||||
{
|
||||
auto ResolveFirstNonEmpty = [](
|
||||
const FString& First,
|
||||
const FString& Second,
|
||||
const FString& Third
|
||||
) -> FString
|
||||
{
|
||||
if (!First.IsEmpty())
|
||||
{
|
||||
return First;
|
||||
}
|
||||
if (!Second.IsEmpty())
|
||||
{
|
||||
return Second;
|
||||
}
|
||||
|
||||
return Third;
|
||||
};
|
||||
|
||||
FHyperTwistTrainingCoachReadinessEligibilitySurface Surface;
|
||||
Surface.Headline = TEXT("Coach Readiness");
|
||||
Surface.ContinuationKind = HandoffContinuationSurface.ContinuationKind;
|
||||
Surface.QueuePostureKind = QueueRecoveryPostureSurface.PostureKind;
|
||||
Surface.bBlockedByActiveRun = PanelState.bHasActiveRun;
|
||||
Surface.bBlockedByQueueSuppression = !PanelState.QueueSuppressionLine.IsEmpty();
|
||||
Surface.bNeedsVerificationAttention = PanelState.bRepositoryVerificationNeedsAttention;
|
||||
|
||||
const bool bHasReadinessPressure = PanelState.bHasCoachGuidance
|
||||
|| PanelState.bHasFollowUpGuidance
|
||||
|| PanelState.bHasQueueWork
|
||||
|| PanelState.bHasDeferredQueueWork
|
||||
|| QueueRecoveryPostureSurface.bHasRecoveryPressure
|
||||
|| WorkloadBudgetSurface.bHasFocusPressure
|
||||
|| WorkloadBudgetSurface.bHasQueueLoad
|
||||
|| WorkloadBudgetSurface.bHasLaunchBudget;
|
||||
|
||||
if (HandoffContinuationSurface.bHasActionableContinuation
|
||||
&& !HandoffContinuationSurface.bQueueRecoveryOverridesContinuation)
|
||||
{
|
||||
Surface.EligibilityKind = EHyperTwistTrainingCoachEligibilityKind::PrimaryAction;
|
||||
Surface.bHasActionableControl = true;
|
||||
Surface.ActionLabel = !HandoffContinuationSurface.ContinuationActionLabel.IsEmpty()
|
||||
? HandoffContinuationSurface.ContinuationActionLabel
|
||||
: PrimaryActionSurface.ActionLabel;
|
||||
Surface.ActionSourceLabel = ResolveFirstNonEmpty(
|
||||
HandoffContinuationSurface.ContinuationSourceLabel,
|
||||
PrimaryActionSurface.ActionSourceLabel,
|
||||
PanelState.PreferredCoachHandoffSourceLabel
|
||||
);
|
||||
Surface.StatusLine = TEXT("Readiness: primary coach continuation is actionable now.");
|
||||
Surface.EligibilityLine = ResolveFirstNonEmpty(
|
||||
HandoffContinuationSurface.StatusLine,
|
||||
PrimaryActionSurface.AvailabilityLine,
|
||||
TEXT("Coach continuation is actionable now.")
|
||||
);
|
||||
}
|
||||
else if (QueueRecoveryPostureSurface.PostureKind
|
||||
== EHyperTwistTrainingCoachQueuePostureKind::Promote
|
||||
&& QueueControlSurface.bCanPromote)
|
||||
{
|
||||
Surface.EligibilityKind = EHyperTwistTrainingCoachEligibilityKind::Promote;
|
||||
Surface.bHasActionableControl = true;
|
||||
Surface.ActionLabel = QueueControlSurface.PromoteActionLabel;
|
||||
Surface.ActionSourceLabel = ResolveFirstNonEmpty(
|
||||
QueueControlSurface.PromoteActionSourceLabel,
|
||||
QueueRecoveryPostureSurface.PreferredActionSourceLabel,
|
||||
PanelState.PreferredQueueRecoveryActionSourceLabel
|
||||
);
|
||||
Surface.StatusLine =
|
||||
TEXT("Readiness: deferred promotion is the actionable next coach control.");
|
||||
Surface.EligibilityLine = ResolveFirstNonEmpty(
|
||||
QueueRecoveryPostureSurface.StatusLine,
|
||||
QueueControlSurface.PromoteAvailabilityLine,
|
||||
TEXT("Deferred promotion is actionable now.")
|
||||
);
|
||||
}
|
||||
else if (QueueRecoveryPostureSurface.PostureKind
|
||||
== EHyperTwistTrainingCoachQueuePostureKind::Defer
|
||||
&& QueueControlSurface.bCanDefer)
|
||||
{
|
||||
Surface.EligibilityKind = EHyperTwistTrainingCoachEligibilityKind::Defer;
|
||||
Surface.bHasActionableControl = true;
|
||||
Surface.ActionLabel = QueueControlSurface.DeferActionLabel;
|
||||
Surface.ActionSourceLabel = ResolveFirstNonEmpty(
|
||||
QueueRecoveryPostureSurface.PreferredActionSourceLabel,
|
||||
PanelState.PreferredQueueRecoveryActionSourceLabel,
|
||||
PanelState.PreferredCoachHandoffSourceLabel
|
||||
);
|
||||
Surface.StatusLine =
|
||||
TEXT("Readiness: defer is the actionable queue-pressure release control.");
|
||||
Surface.EligibilityLine = ResolveFirstNonEmpty(
|
||||
QueueRecoveryPostureSurface.StatusLine,
|
||||
QueueControlSurface.DeferAvailabilityLine,
|
||||
TEXT("Defer is actionable now.")
|
||||
);
|
||||
}
|
||||
else if (PanelState.bHasActiveRun)
|
||||
{
|
||||
Surface.EligibilityKind = EHyperTwistTrainingCoachEligibilityKind::ActiveRunBlocked;
|
||||
Surface.bHasBlockingCondition = true;
|
||||
Surface.StatusLine =
|
||||
TEXT("Readiness: coach continuation is blocked while a training run is already active.");
|
||||
Surface.EligibilityLine = ResolveFirstNonEmpty(
|
||||
HandoffContinuationSurface.StatusLine,
|
||||
PrimaryActionSurface.AvailabilityLine,
|
||||
TEXT("Finish or clear the active run before another coach action can start.")
|
||||
);
|
||||
Surface.BlockedReasonLine =
|
||||
TEXT("A training run is already active.");
|
||||
}
|
||||
else if (!PanelState.QueueSuppressionLine.IsEmpty())
|
||||
{
|
||||
Surface.EligibilityKind = EHyperTwistTrainingCoachEligibilityKind::QueueSuppressed;
|
||||
Surface.bHasBlockingCondition = true;
|
||||
Surface.StatusLine =
|
||||
TEXT("Readiness: no coach action is currently actionable because queue suppression is still active.");
|
||||
Surface.EligibilityLine = PanelState.QueueSuppressionLine;
|
||||
Surface.BlockedReasonLine = PanelState.QueueSuppressionLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.EligibilityKind = EHyperTwistTrainingCoachEligibilityKind::NoEligibleAction;
|
||||
Surface.bHasBlockingCondition = bHasReadinessPressure;
|
||||
if (bHasReadinessPressure)
|
||||
{
|
||||
Surface.StatusLine = TEXT("Readiness: no coach control is actionable right now.");
|
||||
Surface.EligibilityLine = ResolveFirstNonEmpty(
|
||||
HandoffContinuationSurface.StatusLine,
|
||||
QueueRecoveryPostureSurface.StatusLine,
|
||||
ResolveFirstNonEmpty(
|
||||
PrimaryActionSurface.AvailabilityLine,
|
||||
PanelState.SecondaryLine,
|
||||
TEXT("No coach control is currently actionable.")
|
||||
)
|
||||
);
|
||||
Surface.BlockedReasonLine = ResolveFirstNonEmpty(
|
||||
QueueRecoveryPostureSurface.StatusLine,
|
||||
PrimaryActionSurface.AvailabilityLine,
|
||||
Surface.EligibilityLine
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Readiness: coach lane is idle and no action is currently needed.");
|
||||
Surface.EligibilityLine = ResolveFirstNonEmpty(
|
||||
WorkloadBudgetSurface.StatusLine,
|
||||
PanelState.SecondaryLine,
|
||||
TEXT("No queued, follow-up, or recommended coach work is currently materialized.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Surface.ActionSourceDescription =
|
||||
HyperTwistTrainingCoachLibraryInternal::DescribeGameplayCoachSourceLabel(
|
||||
Surface.ActionSourceLabel
|
||||
);
|
||||
|
||||
const FString EligibilityKindLabel =
|
||||
HyperTwistTrainingCoachLibraryInternal::DescribeCoachEligibilityKind(
|
||||
Surface.EligibilityKind
|
||||
);
|
||||
const FString QueuePostureLabel =
|
||||
HyperTwistTrainingCoachLibraryInternal::DescribeCoachQueuePostureKind(
|
||||
Surface.QueuePostureKind
|
||||
);
|
||||
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Eligibility: %s | Action: %s | Source: %s | Continuation: %s | Queue posture: %s | Workload: %s | Verification: %s | Recognition: %s | Review: %s"),
|
||||
*EligibilityKindLabel,
|
||||
Surface.ActionLabel.IsEmpty() ? TEXT("none") : *Surface.ActionLabel,
|
||||
*Surface.ActionSourceDescription,
|
||||
HandoffContinuationSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *HandoffContinuationSurface.StatusLine,
|
||||
*QueuePostureLabel,
|
||||
WorkloadBudgetSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *WorkloadBudgetSurface.StatusLine,
|
||||
PanelState.VerificationStatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *PanelState.VerificationStatusLine,
|
||||
PanelState.RecognitionStatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *PanelState.RecognitionStatusLine,
|
||||
PanelState.ReviewPolicyStatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *PanelState.ReviewPolicyStatusLine
|
||||
);
|
||||
if (!FocusProvenanceSurface.FocusSummaryLine.IsEmpty())
|
||||
{
|
||||
Surface.DetailLine += FString::Printf(
|
||||
TEXT(" | Focus: %s"),
|
||||
*FocusProvenanceSurface.FocusSummaryLine
|
||||
);
|
||||
}
|
||||
if (!Surface.BlockedReasonLine.IsEmpty())
|
||||
{
|
||||
Surface.DetailLine += FString::Printf(
|
||||
TEXT(" | Blocked reason: %s"),
|
||||
*Surface.BlockedReasonLine
|
||||
);
|
||||
}
|
||||
|
||||
return Surface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -559,6 +559,54 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachWorkloadBudgetSurface() const
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
UHyperTwistTrainingPanelWidget::GetDisplayedCoachReadinessEligibilitySurface() const
|
||||
{
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface PrimaryActionSurface =
|
||||
GetDisplayedPrimaryCoachActionSurface();
|
||||
const FHyperTwistTrainingCoachQueueControlSurface QueueControlSurface =
|
||||
GetDisplayedCoachQueueControlSurface();
|
||||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface QueueRecoveryPostureSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachQueueRecoveryPostureSurface(
|
||||
CachedCoachSchedulePolicySummary,
|
||||
CachedCoachQueueExecutionSummary,
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface
|
||||
);
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface HandoffContinuationSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachHandoffContinuationSurface(
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface,
|
||||
QueueRecoveryPostureSurface
|
||||
);
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface FocusProvenanceSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachFocusProvenanceSurface(
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface
|
||||
);
|
||||
const FHyperTwistTrainingCoachWorkloadBudgetSurface WorkloadBudgetSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachWorkloadBudgetSurface(
|
||||
CachedCoachPanelState,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface,
|
||||
FocusProvenanceSurface
|
||||
);
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachReadinessEligibilitySurface(
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface,
|
||||
FocusProvenanceSurface,
|
||||
WorkloadBudgetSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
|
||||
const int32 MaxCases,
|
||||
const FString& StartActionSourceLabel
|
||||
|
|
|
|||
|
|
@ -540,6 +540,54 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachWorkloadBudgetSurface() const
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
AHyperTwistTrainingSessionActor::GetDisplayedCoachReadinessEligibilitySurface() const
|
||||
{
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface PrimaryActionSurface =
|
||||
GetDisplayedPrimaryCoachActionSurface();
|
||||
const FHyperTwistTrainingCoachQueueControlSurface QueueControlSurface =
|
||||
GetDisplayedCoachQueueControlSurface();
|
||||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface QueueRecoveryPostureSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachQueueRecoveryPostureSurface(
|
||||
CachedCoachSchedulePolicySummary,
|
||||
CachedCoachQueueExecutionSummary,
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface
|
||||
);
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface HandoffContinuationSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachHandoffContinuationSurface(
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface,
|
||||
QueueRecoveryPostureSurface
|
||||
);
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface FocusProvenanceSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachFocusProvenanceSurface(
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface
|
||||
);
|
||||
const FHyperTwistTrainingCoachWorkloadBudgetSurface WorkloadBudgetSurface =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachWorkloadBudgetSurface(
|
||||
CachedCoachPanelState,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface,
|
||||
FocusProvenanceSurface
|
||||
);
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachReadinessEligibilitySurface(
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface,
|
||||
FocusProvenanceSurface,
|
||||
WorkloadBudgetSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
|
||||
const int32 MaxCases
|
||||
)
|
||||
|
|
|
|||
|
|
@ -638,4 +638,16 @@ public:
|
|||
const FHyperTwistTrainingCoachHandoffContinuationSurface& HandoffContinuationSurface,
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface& FocusProvenanceSurface
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
DeriveCoachReadinessEligibilitySurface(
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState,
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface& PrimaryActionSurface,
|
||||
const FHyperTwistTrainingCoachQueueControlSurface& QueueControlSurface,
|
||||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface& QueueRecoveryPostureSurface,
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface& HandoffContinuationSurface,
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface& FocusProvenanceSurface,
|
||||
const FHyperTwistTrainingCoachWorkloadBudgetSurface& WorkloadBudgetSurface
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -236,6 +236,10 @@ public:
|
|||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
GetDisplayedCoachWorkloadBudgetSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
GetDisplayedCoachReadinessEligibilitySurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedRun(
|
||||
int32 MaxCases,
|
||||
|
|
|
|||
|
|
@ -217,6 +217,10 @@ public:
|
|||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
GetDisplayedCoachWorkloadBudgetSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
GetDisplayedCoachReadinessEligibilitySurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,18 @@ enum class EHyperTwistTrainingCoachHandoffKind : uint8
|
|||
Recommended UMETA(DisplayName = "Recommended")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingCoachEligibilityKind : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "None"),
|
||||
PrimaryAction UMETA(DisplayName = "Primary Action"),
|
||||
Promote UMETA(DisplayName = "Promote"),
|
||||
Defer UMETA(DisplayName = "Defer"),
|
||||
ActiveRunBlocked UMETA(DisplayName = "Active Run Blocked"),
|
||||
QueueSuppressed UMETA(DisplayName = "Queue Suppressed"),
|
||||
NoEligibleAction UMETA(DisplayName = "No Eligible Action")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingPromptKind : uint8
|
||||
{
|
||||
|
|
@ -8170,3 +8182,68 @@ struct FHyperTwistTrainingCoachWorkloadBudgetSurface
|
|||
|| bHasLaunchBudget;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachReadinessEligibilitySurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString EligibilityLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BlockedReasonLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActionSourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActionSourceDescription;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachEligibilityKind EligibilityKind =
|
||||
EHyperTwistTrainingCoachEligibilityKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachHandoffKind ContinuationKind =
|
||||
EHyperTwistTrainingCoachHandoffKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachQueuePostureKind QueuePostureKind =
|
||||
EHyperTwistTrainingCoachQueuePostureKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasActionableControl = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasBlockingCondition = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBlockedByActiveRun = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBlockedByQueueSuppression = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bNeedsVerificationAttention = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !EligibilityLine.IsEmpty()
|
||||
|| bHasActionableControl
|
||||
|| bHasBlockingCondition;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 coach workload/budget summary surface over the already-landed primary CTA, secondary queue-control, queue-recovery posture, handoff-continuation, and focus/provenance surfaces, so gameplay/Blueprint callers can render launch case budget, queue load, and focus pressure without reading raw count and budget fields directly
|
||||
- the current next bounded packet is to expose one thin coach readiness/eligibility summary surface on those same two consumer surfaces so gameplay/Blueprint callers can render what is actionable now, what is blocked, and why without reading raw booleans or suppression strings directly
|
||||
- the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin coach readiness/eligibility summary surface over the already-landed primary CTA, secondary queue-control, queue-recovery posture, handoff-continuation, focus/provenance, and workload/budget surfaces, so gameplay/Blueprint callers can render what is actionable now, what is blocked, and why without reading raw booleans or suppression strings directly
|
||||
- the current next bounded packet is to expose one thin coach verification / recognition / review-policy context surface on those same two consumer surfaces so gameplay/Blueprint callers can render repository-verification, recognition-provider, and review-policy context without reading raw status/detail lines 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,115 @@
|
|||
# HyperTwist Phase 4 gameplay readiness/eligibility 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 coach helpers by exposing one pure readiness/eligibility summary surface over the already-landed primary coach CTA, queue-control, queue-recovery posture, handoff-continuation, focus/provenance, and workload/budget surfaces.
|
||||
|
||||
The open tasks were:
|
||||
|
||||
- stop forcing gameplay / Blueprint callers to read raw actionability booleans, active-run state, and queue-suppression strings just to explain whether coach work is actionable now
|
||||
- expose one thin first-party readiness/eligibility surface that summarizes the live actionable control, the blocking condition when no control is live, and the direct reason for that blocked state
|
||||
- keep that surface derived from already-cached gameplay consumer state instead of widening into dashboard-only orchestration or backend queue policy
|
||||
|
||||
It is not:
|
||||
|
||||
- a new coach launch policy packet
|
||||
- a queue suppression or queue recovery policy packet
|
||||
- a dashboard actionability migration
|
||||
- a broader gameplay HUD composition pass
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- add a first-party readiness/eligibility surface in shared training types
|
||||
- add a coach-library helper that derives the surface from panel state, the displayed primary CTA surface, the displayed queue-control surface, the displayed queue-recovery posture surface, the displayed handoff-continuation surface, the displayed focus/provenance surface, and the displayed workload/budget surface
|
||||
- expose that derived readiness/eligibility surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`
|
||||
- keep the derivation presentation-only and rooted in already-cached gameplay consumer state
|
||||
|
||||
Out of scope:
|
||||
|
||||
- changing coach continuation branch order
|
||||
- changing queue suppression or queue recovery policy
|
||||
- importing dashboard-only orchestration or retained analytics into gameplay consumers
|
||||
- widening into higher-level gameplay UI composition in the same packet
|
||||
|
||||
## Why this was the right next packet
|
||||
|
||||
Before this slice:
|
||||
|
||||
- gameplay-facing panel/session consumers already exposed truthful primary CTA, queue-control, queue-recovery posture, handoff-continuation, focus/provenance, and workload/budget surfaces
|
||||
|
||||
But one thin consumer seam was still open:
|
||||
|
||||
- callers could bind actions, explain continuation, narrate provenance, and summarize workload
|
||||
- but they still had to inspect raw booleans and queue-suppression text to explain whether coach work was actionable now or blocked
|
||||
|
||||
That meant:
|
||||
|
||||
- action binding was thin
|
||||
- continuation, provenance, and workload explanation were thin
|
||||
- but live readiness explanation still leaked raw panel-state gating into callers
|
||||
|
||||
So the next bounded move was:
|
||||
|
||||
- keep the already-landed action, posture, continuation, provenance, and workload surfaces unchanged
|
||||
- and expose one narrow readiness/eligibility summary surface above them
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
|
||||
- added `EHyperTwistTrainingCoachEligibilityKind`
|
||||
- added `FHyperTwistTrainingCoachReadinessEligibilitySurface`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
|
||||
- added `DeriveCoachReadinessEligibilitySurface(...)`
|
||||
- readiness/eligibility is derived from existing panel-state, primary CTA, queue-control, queue-recovery posture, handoff-continuation, focus/provenance, and workload/budget inputs
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
|
||||
- added `GetDisplayedCoachReadinessEligibilitySurface()`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
|
||||
- added `GetDisplayedCoachReadinessEligibilitySurface()`
|
||||
|
||||
## Product effect
|
||||
|
||||
The gameplay-facing coach consumer layer is now more complete:
|
||||
|
||||
- gameplay / Blueprint callers can read one pure surface to explain whether primary continuation, deferred promotion, or defer is actionable now
|
||||
- callers can also read one direct blocked-reason line when active-run state or queue suppression prevents another coach action
|
||||
- callers no longer need to inspect raw booleans or queue-suppression strings just to narrate live readiness
|
||||
- the surface stays aligned with the already-landed primary CTA, queue-control, queue-recovery posture, handoff-continuation, focus/provenance, and workload/budget surfaces without importing dashboard-only orchestration
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- shared training types expose a narrow readiness/eligibility surface
|
||||
- coach-library derivation consumes already-cached gameplay consumer state rather than adding new runtime fetches
|
||||
- panel-widget callers can fetch the displayed readiness/eligibility surface directly
|
||||
- session-actor callers can fetch the displayed readiness/eligibility surface directly
|
||||
- full product build succeeds
|
||||
|
||||
## Validation checklist
|
||||
|
||||
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
|
||||
2. confirm the new readiness/eligibility surface compiles in shared types and coach library
|
||||
3. confirm panel-widget getters compile and return the derived readiness/eligibility surface
|
||||
4. confirm session-actor getters compile and return the derived readiness/eligibility surface
|
||||
5. confirm no backend continuity or dashboard-only orchestration work was pulled into the packet
|
||||
|
||||
## Validation result
|
||||
|
||||
- full `Development Editor|Win64` build succeeded on `2026-05-08`
|
||||
- build completed with `0` warnings and `0` errors
|
||||
|
||||
## Next bounded follow-on slice
|
||||
|
||||
- stay on the same gameplay-facing consumer lane and expose one thin coach verification / recognition / review-policy context surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`, so gameplay callers can render repository-verification, recognition-provider, and review-policy context without reading raw status/detail lines directly
|
||||
Loading…
Add table
Reference in a new issue