Expose gameplay workload budget surface
This commit is contained in:
parent
53bb7ab349
commit
6db9557751
9 changed files with 417 additions and 2 deletions
|
|
@ -6169,3 +6169,135 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachFocusProvenanceSurface(
|
|||
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachWorkloadBudgetSurface(
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState,
|
||||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface& QueueRecoveryPostureSurface,
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface& HandoffContinuationSurface,
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface& FocusProvenanceSurface
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingCoachWorkloadBudgetSurface Surface;
|
||||
Surface.Headline = TEXT("Coach Workload");
|
||||
Surface.SignalCount = FMath::Max(PanelState.SignalCount, 0);
|
||||
Surface.FocusCaseCount = FMath::Max(PanelState.FocusCaseCount, 0);
|
||||
Surface.SuggestedLaunchCaseBudget = FMath::Max(PanelState.SuggestedLaunchCaseBudget, 0);
|
||||
Surface.TotalQueueEntryCount = FMath::Max(PanelState.TotalQueueEntryCount, 0);
|
||||
Surface.ReadyQueueEntryCount = FMath::Max(PanelState.ReadyQueueEntryCount, 0);
|
||||
Surface.DeferredQueueEntryCount = FMath::Max(PanelState.DeferredQueueEntryCount, 0);
|
||||
Surface.FollowUpQueueEntryCount = FMath::Max(PanelState.FollowUpQueueEntryCount, 0);
|
||||
Surface.PressureScore = FMath::Max(QueueRecoveryPostureSurface.PressureScore, 0.0f);
|
||||
Surface.ContinuationKind = HandoffContinuationSurface.ContinuationKind;
|
||||
Surface.QueuePostureKind = QueueRecoveryPostureSurface.PostureKind;
|
||||
Surface.bHasFocusPressure = Surface.SignalCount > 0 || Surface.FocusCaseCount > 0;
|
||||
Surface.bHasQueueLoad = Surface.TotalQueueEntryCount > 0
|
||||
|| Surface.ReadyQueueEntryCount > 0
|
||||
|| Surface.DeferredQueueEntryCount > 0
|
||||
|| Surface.FollowUpQueueEntryCount > 0;
|
||||
Surface.bHasLaunchBudget = Surface.SuggestedLaunchCaseBudget > 0
|
||||
|| !PanelState.LaunchBudgetReasonLine.IsEmpty();
|
||||
Surface.bHasQueuePressure = QueueRecoveryPostureSurface.bHasRecoveryPressure
|
||||
|| QueueRecoveryPostureSurface.PostureKind
|
||||
!= EHyperTwistTrainingCoachQueuePostureKind::None
|
||||
|| Surface.PressureScore > 0.0f;
|
||||
|
||||
const FString ContinuationKindLabel =
|
||||
HyperTwistTrainingCoachLibraryInternal::DescribeCoachHandoffKind(
|
||||
Surface.ContinuationKind
|
||||
);
|
||||
const FString QueuePostureLabel =
|
||||
HyperTwistTrainingCoachLibraryInternal::DescribeCoachQueuePostureKind(
|
||||
Surface.QueuePostureKind
|
||||
);
|
||||
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Workload: %d signals across %d focus cases | Queue: %d total (%d ready, %d deferred, %d follow-up) | Continuation: %s"),
|
||||
Surface.SignalCount,
|
||||
Surface.FocusCaseCount,
|
||||
Surface.TotalQueueEntryCount,
|
||||
Surface.ReadyQueueEntryCount,
|
||||
Surface.DeferredQueueEntryCount,
|
||||
Surface.FollowUpQueueEntryCount,
|
||||
*ContinuationKindLabel
|
||||
);
|
||||
if (Surface.SuggestedLaunchCaseBudget > 0)
|
||||
{
|
||||
Surface.StatusLine += FString::Printf(
|
||||
TEXT(" | Launch cases: %d"),
|
||||
Surface.SuggestedLaunchCaseBudget
|
||||
);
|
||||
}
|
||||
if (Surface.bHasQueuePressure)
|
||||
{
|
||||
Surface.StatusLine += FString::Printf(
|
||||
TEXT(" | Pressure: %.2f"),
|
||||
Surface.PressureScore
|
||||
);
|
||||
}
|
||||
|
||||
Surface.FocusPressureLine = FString::Printf(
|
||||
TEXT("Focus: %d signals | Cases: %d%s"),
|
||||
Surface.SignalCount,
|
||||
Surface.FocusCaseCount,
|
||||
Surface.SuggestedLaunchCaseBudget > 0
|
||||
? *FString::Printf(
|
||||
TEXT(" | Launch cases: %d"),
|
||||
Surface.SuggestedLaunchCaseBudget)
|
||||
: TEXT("")
|
||||
);
|
||||
|
||||
Surface.QueueLoadLine = !PanelState.QueueStatusLine.IsEmpty()
|
||||
? PanelState.QueueStatusLine
|
||||
: FString::Printf(
|
||||
TEXT("Queue: %d total, %d ready, %d deferred"),
|
||||
Surface.TotalQueueEntryCount,
|
||||
Surface.ReadyQueueEntryCount,
|
||||
Surface.DeferredQueueEntryCount
|
||||
);
|
||||
Surface.QueueLoadLine += FString::Printf(
|
||||
TEXT(" | Follow-up entries: %d"),
|
||||
Surface.FollowUpQueueEntryCount
|
||||
);
|
||||
|
||||
Surface.BudgetLine = Surface.SuggestedLaunchCaseBudget > 0
|
||||
? FString::Printf(
|
||||
TEXT("Launch budget: %d cases"),
|
||||
Surface.SuggestedLaunchCaseBudget
|
||||
)
|
||||
: TEXT("Launch budget: no explicit case budget");
|
||||
if (!FocusProvenanceSurface.LaunchBudgetSourceDescription.IsEmpty()
|
||||
&& FocusProvenanceSurface.LaunchBudgetSourceDescription != TEXT("n/a"))
|
||||
{
|
||||
Surface.BudgetLine += FString::Printf(
|
||||
TEXT(" | Source: %s"),
|
||||
*FocusProvenanceSurface.LaunchBudgetSourceDescription
|
||||
);
|
||||
}
|
||||
if (!PanelState.LaunchBudgetReasonLine.IsEmpty())
|
||||
{
|
||||
Surface.BudgetLine += FString::Printf(
|
||||
TEXT(" | Reason: %s"),
|
||||
*PanelState.LaunchBudgetReasonLine
|
||||
);
|
||||
}
|
||||
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Queue posture: %s | Focus summary: %s | Queue status: %s | Continuation status: %s | Queue recovery: %s"),
|
||||
*QueuePostureLabel,
|
||||
FocusProvenanceSurface.FocusSummaryLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *FocusProvenanceSurface.FocusSummaryLine,
|
||||
PanelState.QueueStatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *PanelState.QueueStatusLine,
|
||||
HandoffContinuationSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *HandoffContinuationSurface.StatusLine,
|
||||
QueueRecoveryPostureSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *QueueRecoveryPostureSurface.StatusLine
|
||||
);
|
||||
|
||||
return Surface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -521,6 +521,44 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachFocusProvenanceSurface() const
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
UHyperTwistTrainingPanelWidget::GetDisplayedCoachWorkloadBudgetSurface() 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
|
||||
);
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachWorkloadBudgetSurface(
|
||||
CachedCoachPanelState,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface,
|
||||
FocusProvenanceSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
|
||||
const int32 MaxCases,
|
||||
const FString& StartActionSourceLabel
|
||||
|
|
|
|||
|
|
@ -502,6 +502,44 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachFocusProvenanceSurface() const
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
AHyperTwistTrainingSessionActor::GetDisplayedCoachWorkloadBudgetSurface() 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
|
||||
);
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachWorkloadBudgetSurface(
|
||||
CachedCoachPanelState,
|
||||
QueueRecoveryPostureSurface,
|
||||
HandoffContinuationSurface,
|
||||
FocusProvenanceSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
|
||||
const int32 MaxCases
|
||||
)
|
||||
|
|
|
|||
|
|
@ -629,4 +629,13 @@ public:
|
|||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface& QueueRecoveryPostureSurface,
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface& HandoffContinuationSurface
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
DeriveCoachWorkloadBudgetSurface(
|
||||
const FHyperTwistTrainingCoachPanelState& PanelState,
|
||||
const FHyperTwistTrainingCoachQueueRecoveryPostureSurface& QueueRecoveryPostureSurface,
|
||||
const FHyperTwistTrainingCoachHandoffContinuationSurface& HandoffContinuationSurface,
|
||||
const FHyperTwistTrainingCoachFocusProvenanceSurface& FocusProvenanceSurface
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -232,6 +232,10 @@ public:
|
|||
FHyperTwistTrainingCoachFocusProvenanceSurface
|
||||
GetDisplayedCoachFocusProvenanceSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
GetDisplayedCoachWorkloadBudgetSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedRun(
|
||||
int32 MaxCases,
|
||||
|
|
|
|||
|
|
@ -213,6 +213,10 @@ public:
|
|||
FHyperTwistTrainingCoachFocusProvenanceSurface
|
||||
GetDisplayedCoachFocusProvenanceSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
GetDisplayedCoachWorkloadBudgetSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);
|
||||
|
||||
|
|
|
|||
|
|
@ -8093,3 +8093,80 @@ struct FHyperTwistTrainingCoachFocusProvenanceSurface
|
|||
|| bHasUpstreamProvenance;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachWorkloadBudgetSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString FocusPressureLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString QueueLoadLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BudgetLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SignalCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FocusCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SuggestedLaunchCaseBudget = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalQueueEntryCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ReadyQueueEntryCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DeferredQueueEntryCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FollowUpQueueEntryCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float PressureScore = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachHandoffKind ContinuationKind =
|
||||
EHyperTwistTrainingCoachHandoffKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachQueuePostureKind QueuePostureKind =
|
||||
EHyperTwistTrainingCoachQueuePostureKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasFocusPressure = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasQueueLoad = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasLaunchBudget = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasQueuePressure = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !BudgetLine.IsEmpty()
|
||||
|| bHasFocusPressure
|
||||
|| bHasQueueLoad
|
||||
|| bHasLaunchBudget;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 focus/provenance summary surface over the already-landed primary CTA, secondary queue-control, queue-recovery posture, and handoff-continuation surfaces, so gameplay/Blueprint callers can render the active coach target and upstream recommendation provenance without reading raw focus ids or source-label strings directly
|
||||
- the current next bounded packet is to expose one thin coach workload/budget summary surface on those same two consumer surfaces so gameplay/Blueprint callers can render launch case budget, queue load, and focus pressure without reading raw count and budget fields directly
|
||||
- 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 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,113 @@
|
|||
# HyperTwist Phase 4 gameplay workload/budget 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 workload/budget summary surface over the already-landed primary coach CTA, queue-control, queue-recovery posture, handoff-continuation, and focus/provenance surfaces.
|
||||
|
||||
The open tasks were:
|
||||
|
||||
- stop forcing gameplay / Blueprint callers to read raw focus-case counts, signal counts, launch-budget counts, queue-entry counts, and pressure scores just to explain current coach workload
|
||||
- expose one thin first-party workload/budget surface that summarizes focus pressure, queue load, launch-case budget, and live continuation / queue-pressure posture
|
||||
- keep that surface derived from already-cached gameplay consumer state instead of widening into dashboard-only retained analytics or backend scheduling policy
|
||||
|
||||
It is not:
|
||||
|
||||
- a new coach scheduling or launch-budget policy packet
|
||||
- a queue recovery selection-policy packet
|
||||
- a dashboard workload migration
|
||||
- a broader gameplay HUD composition pass
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- add a first-party workload/budget surface in shared training types
|
||||
- add a coach-library helper that derives the surface from panel state, the displayed queue-recovery posture surface, the displayed handoff-continuation surface, and the displayed focus/provenance surface
|
||||
- expose that derived workload/budget 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 recovery or launch-budget policy
|
||||
- importing dashboard-only retained workload 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, and focus/provenance surfaces
|
||||
|
||||
But one thin consumer seam was still open:
|
||||
|
||||
- callers could bind actions, explain continuation, and narrate focus/provenance
|
||||
- but they still had to inspect raw counts and budget fields to explain how much work was live, how much queue load remained, and why a given launch-case budget existed
|
||||
|
||||
That meant:
|
||||
|
||||
- action binding was thin
|
||||
- continuation and provenance explanation were thin
|
||||
- but workload and budget explanation still leaked raw panel-state values into callers
|
||||
|
||||
So the next bounded move was:
|
||||
|
||||
- keep the already-landed action, posture, continuation, and provenance surfaces unchanged
|
||||
- and expose one narrow workload/budget summary surface above them
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
|
||||
- added `FHyperTwistTrainingCoachWorkloadBudgetSurface`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
|
||||
- added `DeriveCoachWorkloadBudgetSurface(...)`
|
||||
- workload/budget is derived from existing panel-state, queue-recovery posture, handoff-continuation, and focus/provenance inputs
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
|
||||
- added `GetDisplayedCoachWorkloadBudgetSurface()`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
|
||||
- added `GetDisplayedCoachWorkloadBudgetSurface()`
|
||||
|
||||
## Product effect
|
||||
|
||||
The gameplay-facing coach consumer layer is now more complete:
|
||||
|
||||
- gameplay / Blueprint callers can read one pure surface to describe focus pressure, queue load, launch-case budget, and live queue-pressure posture
|
||||
- callers no longer need to inspect raw count fields, launch-budget fields, or queue-status fragments just to render workload narration
|
||||
- the surface stays aligned with the already-landed primary CTA, queue-control, queue-recovery posture, handoff-continuation, and focus/provenance surfaces without importing dashboard-only retained workload analytics
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- shared training types expose a narrow workload/budget surface
|
||||
- coach-library derivation consumes already-cached gameplay consumer state rather than adding new runtime fetches
|
||||
- panel-widget callers can fetch the displayed workload/budget surface directly
|
||||
- session-actor callers can fetch the displayed workload/budget surface directly
|
||||
- full product build succeeds
|
||||
|
||||
## Validation checklist
|
||||
|
||||
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
|
||||
2. confirm the new workload/budget surface compiles in shared types and coach library
|
||||
3. confirm panel-widget getters compile and return the derived workload/budget surface
|
||||
4. confirm session-actor getters compile and return the derived workload/budget surface
|
||||
5. confirm no backend continuity or dashboard-only retained analytics 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 readiness/eligibility summary surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`, so gameplay callers can render what is actionable now, what is blocked, and why without reading raw booleans or suppression strings directly
|
||||
Loading…
Add table
Reference in a new issue