Explain closure policy in schedule summary

This commit is contained in:
axiomlogicnexus 2026-04-27 20:16:12 +02:00
parent 5f2278afba
commit 602abb8de9
5 changed files with 55 additions and 2 deletions

View file

@ -1542,6 +1542,7 @@ FHyperTwistCoachSchedulePolicySummary UHyperTwistContractLibrary::MakeSampleTrai
return UHyperTwistTrainingCoachLibrary::DeriveCoachSchedulePolicySummary(
MakeSampleTrainingCoachSessionQueueState(),
MakeSampleTrainingCoachScheduleHorizonSummary(),
MakeSampleTrainingCoachActionClosureSummary(),
MakeSampleTrainingCoachArchivePolicySummary(),
TEXT("2026-04-28T12:30:00Z")
);

View file

@ -5279,7 +5279,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
if (SchedulePolicyTextBlock != nullptr)
{
SchedulePolicyTextBlock->SetText(FText::FromString(FString::Printf(
TEXT("Policy: immediate %d | pending %d | deferred %d | manual %d | earliest deferred: %s | dominant reason: %s | pressure %.2f | manual allowed: %s | expired deferrals: %s | review needed: %s | archive-aware: %s | blocked follow-up: %s"),
TEXT("Policy: immediate %d | pending %d | deferred %d | manual %d | earliest deferred: %s | dominant reason: %s | pressure %.2f | manual allowed: %s | expired deferrals: %s | review needed: %s | archive-aware: %s | blocked follow-up: %s | closure: %s"),
CachedCoachSchedulePolicySummary.ImmediateEntryCount,
CachedCoachSchedulePolicySummary.PendingEntryCount,
CachedCoachSchedulePolicySummary.DeferredEntryCount,
@ -5295,7 +5295,10 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
CachedCoachSchedulePolicySummary.bHasExpiredDeferrals ? TEXT("yes") : TEXT("no"),
CachedCoachSchedulePolicySummary.bNeedsManualRescheduleReview ? TEXT("yes") : TEXT("no"),
CachedCoachSchedulePolicySummary.bHasArchiveAwareDeferrals ? TEXT("yes") : TEXT("no"),
CachedCoachSchedulePolicySummary.bHasBlockedFollowUpDeferrals ? TEXT("yes") : TEXT("no")
CachedCoachSchedulePolicySummary.bHasBlockedFollowUpDeferrals ? TEXT("yes") : TEXT("no"),
CachedCoachSchedulePolicySummary.ClosurePolicyLine.IsEmpty()
? TEXT("n/a")
: *CachedCoachSchedulePolicySummary.ClosurePolicyLine
)));
}
if (QueueRecoveryHeaderTextBlock != nullptr)

View file

@ -1593,6 +1593,7 @@ FHyperTwistCoachScheduleHorizonSummary UHyperTwistTrainingCoachLibrary::DeriveCo
FHyperTwistCoachSchedulePolicySummary UHyperTwistTrainingCoachLibrary::DeriveCoachSchedulePolicySummary(
const FHyperTwistTrainingCoachSessionQueueState& QueueState,
const FHyperTwistCoachScheduleHorizonSummary& HorizonSummary,
const FHyperTwistTrainingCoachActionClosureSummary& ClosureSummary,
const FHyperTwistTrainingCoachArchivePolicySummary& ArchivePolicySummary,
const FString& ReferenceUtc
)
@ -1695,9 +1696,46 @@ FHyperTwistCoachSchedulePolicySummary UHyperTwistTrainingCoachLibrary::DeriveCoa
Summary.bHasArchiveAwareDeferrals = Summary.ArchiveAwareDeferredEntryCount > 0
|| (ArchivePolicySummary.bNeedsArchiveRetentionTuning && Summary.DeferredEntryCount > 0);
Summary.bHasBlockedFollowUpDeferrals = Summary.BlockedFollowUpDeferredEntryCount > 0;
Summary.bFollowUpContinuationFromRecoveryHistory =
ClosureSummary.bSpawnFollowUpFromSuppressionMemory;
Summary.bBorderlineFollowUpSuppressedByRecoveryHistory =
ClosureSummary.bSuppressedBorderlineFollowUpByRecoveryHistory;
Summary.bNeedsManualRescheduleReview = Summary.bHasExpiredDeferrals
|| Summary.ManualRescheduleEntryCount >= 2
|| Summary.bHasBlockedFollowUpDeferrals;
if (ClosureSummary.IsStructurallyValid())
{
if (Summary.bFollowUpContinuationFromRecoveryHistory)
{
Summary.ClosurePolicyLine =
TEXT("Closure policy: recovery history keeps follow-up alive on carry-forward pressure.");
}
else if (Summary.bBorderlineFollowUpSuppressedByRecoveryHistory)
{
Summary.ClosurePolicyLine =
TEXT("Closure policy: recommended recovery history suppresses a borderline follow-up.");
}
else if (ClosureSummary.bShouldSpawnFollowUp)
{
Summary.ClosurePolicyLine =
TEXT("Closure policy: unresolved or weak cases still require follow-up.");
}
else if (ClosureSummary.bNeedsEscalation)
{
Summary.ClosurePolicyLine =
TEXT("Closure policy: escalation takes precedence over additional follow-up.");
}
else if (ClosureSummary.bSequenceClosed)
{
Summary.ClosurePolicyLine =
TEXT("Closure policy: sequence is closed and resolved work can archive forward.");
}
else
{
Summary.ClosurePolicyLine =
TEXT("Closure policy: sequence remains stable without spawning new follow-up.");
}
}
Summary.ReschedulePressureScore = FMath::Clamp(
static_cast<float>(Summary.DeferredEntryCount) * 8.0f
+ static_cast<float>(Summary.ManualRescheduleEntryCount) * 10.0f

View file

@ -2302,6 +2302,7 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
ActiveCoachSchedulePolicySummary = UHyperTwistTrainingCoachLibrary::DeriveCoachSchedulePolicySummary(
ActiveCoachSessionQueueState,
ActiveCoachScheduleHorizonSummary,
ActiveCoachActionClosureSummary,
ActiveCoachArchivePolicySummary,
ActiveLearnerDeckStateSummary.ReferenceUtc
);

View file

@ -361,6 +361,9 @@ struct FHyperTwistCoachSchedulePolicySummary
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DominantDeferralReasonLabel;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ClosurePolicyLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ImmediateEntryCount = 0;
@ -397,6 +400,12 @@ struct FHyperTwistCoachSchedulePolicySummary
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasBlockedFollowUpDeferrals = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bFollowUpContinuationFromRecoveryHistory = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bBorderlineFollowUpSuppressedByRecoveryHistory = false;
bool IsStructurallyValid() const
{
return !UserId.IsEmpty() && !QueueId.IsEmpty();
@ -474,6 +483,7 @@ public:
static FHyperTwistCoachSchedulePolicySummary DeriveCoachSchedulePolicySummary(
const FHyperTwistTrainingCoachSessionQueueState& QueueState,
const FHyperTwistCoachScheduleHorizonSummary& HorizonSummary,
const FHyperTwistTrainingCoachActionClosureSummary& ClosureSummary,
const FHyperTwistTrainingCoachArchivePolicySummary& ArchivePolicySummary,
const FString& ReferenceUtc
);