Expose gameplay queue-recovery posture surface
This commit is contained in:
parent
8ffee266a4
commit
82b470b02b
9 changed files with 432 additions and 2 deletions
|
|
@ -5571,3 +5571,209 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachQueueControlSurface(
|
|||
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachQueueRecoveryPostureSurface(
|
||||
const FHyperTwistCoachSchedulePolicySummary& SchedulePolicySummary,
|
||||
const FHyperTwistTrainingCoachSessionQueueExecutionSummary& QueueExecutionSummary,
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState,
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface& PrimaryActionSurface,
|
||||
const FHyperTwistTrainingCoachQueueControlSurface& QueueControlSurface
|
||||
)
|
||||
{
|
||||
auto DescribeGuidanceLane = [](const EHyperTwistTrainingCoachGuidanceLane Lane) -> FString
|
||||
{
|
||||
switch (Lane)
|
||||
{
|
||||
case EHyperTwistTrainingCoachGuidanceLane::FollowUp:
|
||||
return TEXT("follow-up");
|
||||
case EHyperTwistTrainingCoachGuidanceLane::Recommended:
|
||||
return TEXT("recommended");
|
||||
default:
|
||||
return TEXT("none");
|
||||
}
|
||||
};
|
||||
auto DescribeRecoveryAction = [](const EHyperTwistTrainingQueueRecoveryAction Action) -> FString
|
||||
{
|
||||
switch (Action)
|
||||
{
|
||||
case EHyperTwistTrainingQueueRecoveryAction::PromoteDeferred:
|
||||
return TEXT("prefer promote-deferred recovery");
|
||||
case EHyperTwistTrainingQueueRecoveryAction::LaunchRecovery:
|
||||
return TEXT("prefer launch-recovery");
|
||||
default:
|
||||
return TEXT("no upstream recovery preference");
|
||||
}
|
||||
};
|
||||
|
||||
FHyperTwistTrainingCoachQueueRecoveryPostureSurface Surface;
|
||||
Surface.Headline = TEXT("Queue Recovery");
|
||||
Surface.PreferredRecoveryAction = PanelState.PreferredQueueRecoveryAction;
|
||||
Surface.PreferredGuidanceLane = PanelState.PreferredGuidanceLane;
|
||||
Surface.PressureScore = FMath::Max(
|
||||
SchedulePolicySummary.ReschedulePressureScore,
|
||||
QueueExecutionSummary.ExecutionPressureScore
|
||||
);
|
||||
Surface.bHasRecoveryPressure =
|
||||
Surface.PressureScore > 0.0f
|
||||
|| PanelState.bHasDeferredQueueWork
|
||||
|| QueueExecutionSummary.bHasOutstandingDeferredWork
|
||||
|| QueueExecutionSummary.bHasCompletionGap
|
||||
|| SchedulePolicySummary.bNeedsManualRescheduleReview
|
||||
|| SchedulePolicySummary.bHasExpiredDeferrals
|
||||
|| SchedulePolicySummary.bHasArchiveAwareDeferrals
|
||||
|| SchedulePolicySummary.bHasBlockedFollowUpDeferrals
|
||||
|| PanelState.PreferredQueueRecoveryAction != EHyperTwistTrainingQueueRecoveryAction::None
|
||||
|| HyperTwistTrainingCoachLibraryInternal::IsQueueRecoveryMemorySource(
|
||||
PanelState.PreferredGuidanceSourceLabel
|
||||
);
|
||||
|
||||
const bool bPrefersPromoteUpstream =
|
||||
PanelState.PreferredQueueRecoveryAction
|
||||
== EHyperTwistTrainingQueueRecoveryAction::PromoteDeferred;
|
||||
const bool bPrefersLaunchUpstream =
|
||||
PanelState.PreferredQueueRecoveryAction
|
||||
== EHyperTwistTrainingQueueRecoveryAction::LaunchRecovery;
|
||||
|
||||
if (bPrefersPromoteUpstream && QueueControlSurface.bCanPromote)
|
||||
{
|
||||
Surface.PostureKind = EHyperTwistTrainingCoachQueuePostureKind::Promote;
|
||||
}
|
||||
else if (PrimaryActionSurface.bCanExecute
|
||||
&& (bPrefersLaunchUpstream
|
||||
|| !QueueControlSurface.bCanPromote
|
||||
|| PanelState.PreferredQueueRecoveryAction
|
||||
== EHyperTwistTrainingQueueRecoveryAction::None))
|
||||
{
|
||||
Surface.PostureKind = EHyperTwistTrainingCoachQueuePostureKind::Continue;
|
||||
}
|
||||
else if (QueueControlSurface.bCanPromote)
|
||||
{
|
||||
Surface.PostureKind = EHyperTwistTrainingCoachQueuePostureKind::Promote;
|
||||
}
|
||||
else if (PrimaryActionSurface.bCanExecute)
|
||||
{
|
||||
Surface.PostureKind = EHyperTwistTrainingCoachQueuePostureKind::Continue;
|
||||
}
|
||||
else if (QueueControlSurface.bCanDefer)
|
||||
{
|
||||
Surface.PostureKind = EHyperTwistTrainingCoachQueuePostureKind::Defer;
|
||||
}
|
||||
|
||||
switch (Surface.PostureKind)
|
||||
{
|
||||
case EHyperTwistTrainingCoachQueuePostureKind::Continue:
|
||||
Surface.PreferredActionLabel = PrimaryActionSurface.ActionLabel;
|
||||
Surface.PreferredActionSourceLabel = PrimaryActionSurface.ActionSourceLabel;
|
||||
Surface.bCanExecutePreferredAction = PrimaryActionSurface.bCanExecute;
|
||||
if (bPrefersLaunchUpstream)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Queue recovery keeps continue live as the preferred launch-recovery posture: %s"),
|
||||
PrimaryActionSurface.AvailabilityLine.IsEmpty()
|
||||
? TEXT("Continue is actionable")
|
||||
: *PrimaryActionSurface.AvailabilityLine
|
||||
);
|
||||
}
|
||||
else if (bPrefersPromoteUpstream && !QueueControlSurface.bCanPromote)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Queue recovery falls back to continue because no deferred promote target is currently actionable: %s"),
|
||||
PrimaryActionSurface.AvailabilityLine.IsEmpty()
|
||||
? TEXT("Continue is actionable")
|
||||
: *PrimaryActionSurface.AvailabilityLine
|
||||
);
|
||||
}
|
||||
else if (Surface.bHasRecoveryPressure)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Queue recovery keeps continue as the live actionable posture: %s"),
|
||||
PrimaryActionSurface.AvailabilityLine.IsEmpty()
|
||||
? TEXT("Continue is actionable")
|
||||
: *PrimaryActionSurface.AvailabilityLine
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Queue posture is stable; continue remains the live coach action: %s"),
|
||||
PrimaryActionSurface.AvailabilityLine.IsEmpty()
|
||||
? TEXT("Continue is actionable")
|
||||
: *PrimaryActionSurface.AvailabilityLine
|
||||
);
|
||||
}
|
||||
break;
|
||||
case EHyperTwistTrainingCoachQueuePostureKind::Promote:
|
||||
Surface.PreferredActionLabel = QueueControlSurface.PromoteActionLabel;
|
||||
Surface.PreferredActionSourceLabel = QueueControlSurface.PromoteActionSourceLabel;
|
||||
Surface.bCanExecutePreferredAction = QueueControlSurface.bCanPromote;
|
||||
Surface.StatusLine = bPrefersPromoteUpstream
|
||||
? FString::Printf(
|
||||
TEXT("Queue recovery prefers deferred promotion: %s"),
|
||||
QueueControlSurface.PromoteAvailabilityLine.IsEmpty()
|
||||
? TEXT("Promote is actionable")
|
||||
: *QueueControlSurface.PromoteAvailabilityLine
|
||||
)
|
||||
: FString::Printf(
|
||||
TEXT("Continue is not currently the preferred recovery path, so deferred promotion becomes the live posture: %s"),
|
||||
QueueControlSurface.PromoteAvailabilityLine.IsEmpty()
|
||||
? TEXT("Promote is actionable")
|
||||
: *QueueControlSurface.PromoteAvailabilityLine
|
||||
);
|
||||
break;
|
||||
case EHyperTwistTrainingCoachQueuePostureKind::Defer:
|
||||
Surface.PreferredActionLabel = QueueControlSurface.DeferActionLabel;
|
||||
Surface.bCanExecutePreferredAction = QueueControlSurface.bCanDefer;
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("No continue or promote target is currently actionable; defer is the available queue-pressure release control: %s"),
|
||||
QueueControlSurface.DeferAvailabilityLine.IsEmpty()
|
||||
? TEXT("Defer is actionable")
|
||||
: *QueueControlSurface.DeferAvailabilityLine
|
||||
);
|
||||
break;
|
||||
default:
|
||||
Surface.StatusLine = Surface.bHasRecoveryPressure
|
||||
? TEXT("Queue recovery pressure is present, but no continue, defer, or promote control is currently actionable.")
|
||||
: TEXT("Queue recovery pressure is not currently active.");
|
||||
break;
|
||||
}
|
||||
|
||||
const FString GuidanceLaneLabel = DescribeGuidanceLane(PanelState.PreferredGuidanceLane);
|
||||
const FString GuidanceSourceLabel = PanelState.PreferredGuidanceSourceLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: HyperTwistTrainingCoachLibraryInternal::DescribeCoachMemorySourceLabel(
|
||||
PanelState.PreferredGuidanceSourceLabel
|
||||
);
|
||||
const FString RecoveryActionSourceLabel = PanelState.PreferredQueueRecoveryActionSourceLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: HyperTwistTrainingCoachLibraryInternal::DescribeCoachMemorySourceLabel(
|
||||
PanelState.PreferredQueueRecoveryActionSourceLabel
|
||||
);
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Upstream: %s | Lane: %s | Guidance source: %s | Recovery action source: %s | Pressure %.2f | Runnable queue: %s | Deferred work: %s | Outstanding deferred: %s | Completion gap: %s | Manual review: %s | Blocked follow-up: %s | Archive-aware: %s | Dominant reason: %s"),
|
||||
*DescribeRecoveryAction(PanelState.PreferredQueueRecoveryAction),
|
||||
*GuidanceLaneLabel,
|
||||
*GuidanceSourceLabel,
|
||||
*RecoveryActionSourceLabel,
|
||||
Surface.PressureScore,
|
||||
PanelState.bHasRunnableQueueEntry ? TEXT("yes") : TEXT("no"),
|
||||
PanelState.bHasDeferredQueueWork ? TEXT("yes") : TEXT("no"),
|
||||
QueueExecutionSummary.bHasOutstandingDeferredWork ? TEXT("yes") : TEXT("no"),
|
||||
QueueExecutionSummary.bHasCompletionGap ? TEXT("yes") : TEXT("no"),
|
||||
SchedulePolicySummary.bNeedsManualRescheduleReview ? TEXT("yes") : TEXT("no"),
|
||||
SchedulePolicySummary.bHasBlockedFollowUpDeferrals ? TEXT("yes") : TEXT("no"),
|
||||
SchedulePolicySummary.bHasArchiveAwareDeferrals ? TEXT("yes") : TEXT("no"),
|
||||
SchedulePolicySummary.DominantDeferralReasonLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *SchedulePolicySummary.DominantDeferralReasonLabel
|
||||
);
|
||||
if (!PanelState.QueueSuppressionLine.IsEmpty())
|
||||
{
|
||||
Surface.DetailLine += FString::Printf(
|
||||
TEXT(" | Suppression: %s"),
|
||||
*PanelState.QueueSuppressionLine
|
||||
);
|
||||
}
|
||||
|
||||
return Surface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -451,6 +451,22 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachQueueControlSurface() const
|
|||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
UHyperTwistTrainingPanelWidget::GetDisplayedCoachQueueRecoveryPostureSurface() const
|
||||
{
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface PrimaryActionSurface =
|
||||
GetDisplayedPrimaryCoachActionSurface();
|
||||
const FHyperTwistTrainingCoachQueueControlSurface QueueControlSurface =
|
||||
GetDisplayedCoachQueueControlSurface();
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachQueueRecoveryPostureSurface(
|
||||
CachedCoachSchedulePolicySummary,
|
||||
CachedCoachQueueExecutionSummary,
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
|
||||
const int32 MaxCases,
|
||||
const FString& StartActionSourceLabel
|
||||
|
|
|
|||
|
|
@ -432,6 +432,22 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachQueueControlSurface() const
|
|||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
AHyperTwistTrainingSessionActor::GetDisplayedCoachQueueRecoveryPostureSurface() const
|
||||
{
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface PrimaryActionSurface =
|
||||
GetDisplayedPrimaryCoachActionSurface();
|
||||
const FHyperTwistTrainingCoachQueueControlSurface QueueControlSurface =
|
||||
GetDisplayedCoachQueueControlSurface();
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachQueueRecoveryPostureSurface(
|
||||
CachedCoachSchedulePolicySummary,
|
||||
CachedCoachQueueExecutionSummary,
|
||||
CachedCoachPanelState,
|
||||
PrimaryActionSurface,
|
||||
QueueControlSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
|
||||
const int32 MaxCases
|
||||
)
|
||||
|
|
|
|||
|
|
@ -600,4 +600,14 @@ public:
|
|||
const FHyperTwistTrainingCoachSessionQueueState& QueueState,
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
DeriveCoachQueueRecoveryPostureSurface(
|
||||
const FHyperTwistCoachSchedulePolicySummary& SchedulePolicySummary,
|
||||
const FHyperTwistTrainingCoachSessionQueueExecutionSummary& QueueExecutionSummary,
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState,
|
||||
const FHyperTwistTrainingCoachPrimaryActionSurface& PrimaryActionSurface,
|
||||
const FHyperTwistTrainingCoachQueueControlSurface& QueueControlSurface
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -220,6 +220,10 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachQueueControlSurface GetDisplayedCoachQueueControlSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
GetDisplayedCoachQueueRecoveryPostureSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedRun(
|
||||
int32 MaxCases,
|
||||
|
|
|
|||
|
|
@ -201,6 +201,10 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachQueueControlSurface GetDisplayedCoachQueueControlSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
GetDisplayedCoachQueueRecoveryPostureSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,15 @@ enum class EHyperTwistTrainingQueueRecoveryAction : uint8
|
|||
LaunchRecovery UMETA(DisplayName = "Launch Recovery")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingCoachQueuePostureKind : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "None"),
|
||||
Continue UMETA(DisplayName = "Continue"),
|
||||
Defer UMETA(DisplayName = "Defer"),
|
||||
Promote UMETA(DisplayName = "Promote")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingCoachHandoffKind : uint8
|
||||
{
|
||||
|
|
@ -7908,3 +7917,53 @@ struct FHyperTwistTrainingCoachQueueControlSurface
|
|||
|| !PromoteAvailabilityLine.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachQueueRecoveryPostureSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreferredActionLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreferredActionSourceLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float PressureScore = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachQueuePostureKind PostureKind =
|
||||
EHyperTwistTrainingCoachQueuePostureKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingQueueRecoveryAction PreferredRecoveryAction =
|
||||
EHyperTwistTrainingQueueRecoveryAction::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachGuidanceLane PreferredGuidanceLane =
|
||||
EHyperTwistTrainingCoachGuidanceLane::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasRecoveryPressure = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCanExecutePreferredAction = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !DetailLine.IsEmpty()
|
||||
|| PostureKind != EHyperTwistTrainingCoachQueuePostureKind::None
|
||||
|| bHasRecoveryPressure;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 the matching thin secondary queue-control descriptor / availability surface for defer and promote flows on those same two consumer surfaces, while also aligning their displayed promote path with the same deferred-entry recovery ranking already used by the dashboard
|
||||
- the current next bounded packet is to expose one thin queue-recovery posture / status surface on those same two consumer surfaces so gameplay/Blueprint callers can explain why continue, defer, or promote is preferred without reading raw suppression/status strings or recovery enums directly
|
||||
- the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin queue-recovery posture / status surface over the already-landed primary CTA and secondary queue-control surfaces, so gameplay/Blueprint callers can explain why continue, defer, or promote is preferred without reading raw suppression/status strings or recovery enums directly
|
||||
- the current next bounded packet is to expose one thin coach handoff recommendation / continuation status surface on those same two consumer surfaces so gameplay/Blueprint callers can render the queued-vs-follow-up-vs-recommended continuation posture without reaching into raw panel-state strings or handoff enums 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 queue-recovery posture surface packet
|
||||
|
||||
Created on `2026-05-07`
|
||||
|
||||
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 queue-recovery posture / status surface over the already-landed primary coach CTA and secondary queue-control surfaces.
|
||||
|
||||
The open tasks were:
|
||||
|
||||
- stop forcing gameplay / Blueprint callers to read raw queue suppression strings, queue status strings, and queue-recovery enums just to explain why continue, defer, or promote is currently preferred
|
||||
- expose one thin first-party posture surface that summarizes the live queue-recovery pressure, the currently preferred posture, and the upstream recovery provenance
|
||||
- keep that posture surface derived from already-cached policy, execution, primary CTA, and queue-control state instead of widening into dashboard-only recovery analytics
|
||||
|
||||
It is not:
|
||||
|
||||
- a new recovery-policy packet
|
||||
- a dashboard weighting migration
|
||||
- a broader gameplay HUD composition pass
|
||||
- a backend continuity or template-analytics packet
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- add a first-party queue posture kind enum and queue-recovery posture/status surface in shared training types
|
||||
- add a coach-library helper that derives the surface from schedule-policy summary, queue-execution summary, panel state, primary CTA surface, and queue-control surface
|
||||
- expose that derived posture surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`
|
||||
- keep the posture derivation presentation-only and rooted in already-cached gameplay consumer state
|
||||
|
||||
Out of scope:
|
||||
|
||||
- changing queue recovery selection policy
|
||||
- importing the dashboard’s deeper learned recovery weighting into gameplay consumer surfaces
|
||||
- adding new queue action verbs
|
||||
- widening into handoff recommendation composition in the same packet
|
||||
|
||||
## Why this was the right next packet
|
||||
|
||||
Before this slice:
|
||||
|
||||
- gameplay-facing panel/session consumers already exposed displayed coach-action helpers
|
||||
- those surfaces already exposed a truthful primary CTA surface
|
||||
- those surfaces already exposed a truthful secondary queue-control surface for defer and promote flows
|
||||
|
||||
But one thin consumer seam was still open:
|
||||
|
||||
- callers could bind the actions
|
||||
- but they still had to inspect raw queue suppression/status text and recovery enums to explain why continue, defer, or promote was the current posture
|
||||
|
||||
That meant:
|
||||
|
||||
- action binding was thin
|
||||
- but posture explanation still leaked raw backend-derived strings into callers
|
||||
|
||||
So the next bounded move was:
|
||||
|
||||
- keep the already-landed execution and control surfaces unchanged
|
||||
- and expose one narrow posture/status surface above them
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
|
||||
- added `EHyperTwistTrainingCoachQueuePostureKind`
|
||||
- added `FHyperTwistTrainingCoachQueueRecoveryPostureSurface`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
|
||||
- added `DeriveCoachQueueRecoveryPostureSurface(...)`
|
||||
- posture is derived from existing schedule-policy, queue-execution, panel-state, primary CTA, and queue-control inputs
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
|
||||
- added `GetDisplayedCoachQueueRecoveryPostureSurface()`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
|
||||
- added `GetDisplayedCoachQueueRecoveryPostureSurface()`
|
||||
|
||||
## Product effect
|
||||
|
||||
The gameplay-facing coach consumer layer is now more complete:
|
||||
|
||||
- gameplay / Blueprint callers can explain the live queue-recovery posture from one pure surface
|
||||
- callers no longer need to read raw queue suppression/status strings or queue-recovery enums just to explain why continue, defer, or promote is preferred
|
||||
- the posture surface stays aligned with the already-landed primary CTA and queue-control surfaces without importing dashboard-only recovery analytics
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- shared training types expose a queue posture kind enum and a narrow queue-recovery posture surface
|
||||
- coach-library derivation consumes the already-cached gameplay consumer state rather than adding new runtime fetches
|
||||
- panel-widget callers can fetch the displayed queue-recovery posture surface directly
|
||||
- session-actor callers can fetch the displayed queue-recovery posture surface directly
|
||||
- full product build succeeds
|
||||
|
||||
## Validation checklist
|
||||
|
||||
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
|
||||
2. confirm the new posture surface compiles in shared types and coach library
|
||||
3. confirm panel-widget getters compile and return the derived surface
|
||||
4. confirm session-actor getters compile and return the derived surface
|
||||
5. confirm no backend continuity or dashboard-only recovery weighting work was pulled into the packet
|
||||
|
||||
## Validation result
|
||||
|
||||
- full `Development Editor|Win64` build succeeded on `2026-05-07`
|
||||
- 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 handoff recommendation / continuation status surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`, so gameplay callers can render the queued-vs-follow-up-vs-recommended continuation posture without reaching into raw panel-state strings or handoff enums directly
|
||||
Loading…
Add table
Reference in a new issue