Explain closure recovery through coach brief
This commit is contained in:
parent
457d77b334
commit
c8c879dc7e
3 changed files with 200 additions and 0 deletions
|
|
@ -1494,6 +1494,179 @@ FHyperTwistCoachBrief UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithQueue
|
|||
return Brief;
|
||||
}
|
||||
|
||||
FHyperTwistCoachSignal UHyperTwistTrainingCoachLibrary::DeriveClosureRecoveryHistorySignal(
|
||||
const FHyperTwistTrainingCoachActionClosureSummary& ClosureSummary,
|
||||
const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot,
|
||||
const FHyperTwistCoachBrief& CurrentBrief)
|
||||
{
|
||||
if (!ClosureSummary.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistCoachSignal();
|
||||
}
|
||||
|
||||
const int32 SustainedHistoryCount = CoachMemorySnapshot.RecoverySustainedFollowUpHistoryCount;
|
||||
const int32 SuppressedHistoryCount =
|
||||
CoachMemorySnapshot.RecoverySuppressedBorderlineFollowUpHistoryCount;
|
||||
if (SustainedHistoryCount <= 0 && SuppressedHistoryCount <= 0)
|
||||
{
|
||||
return FHyperTwistCoachSignal();
|
||||
}
|
||||
|
||||
const bool bHistoryPrefersFollowUp = SustainedHistoryCount > SuppressedHistoryCount;
|
||||
const bool bHistoryPrefersRecommended = SuppressedHistoryCount > SustainedHistoryCount;
|
||||
if (!bHistoryPrefersFollowUp && !bHistoryPrefersRecommended)
|
||||
{
|
||||
return FHyperTwistCoachSignal();
|
||||
}
|
||||
|
||||
const bool bCurrentFollowUpContinuation =
|
||||
ClosureSummary.bSpawnFollowUpFromSuppressionMemory;
|
||||
const bool bCurrentBorderlineSuppression =
|
||||
ClosureSummary.bSuppressedBorderlineFollowUpByRecoveryHistory;
|
||||
const bool bCompetingGuidancePressure =
|
||||
CoachMemorySnapshot.RecommendedGuidanceContinueBias > 0
|
||||
&& CoachMemorySnapshot.FollowUpGuidanceContinueBias > 0;
|
||||
|
||||
const float Score = FMath::Clamp(
|
||||
(bHistoryPrefersFollowUp ? 64.0f : 60.0f)
|
||||
+ static_cast<float>(FMath::Max(SustainedHistoryCount, SuppressedHistoryCount)) * 4.0f
|
||||
+ (bCurrentFollowUpContinuation || bCurrentBorderlineSuppression ? 6.0f : 0.0f)
|
||||
+ (bCompetingGuidancePressure ? 4.0f : 0.0f),
|
||||
0.0f,
|
||||
100.0f
|
||||
);
|
||||
const FString SignalId = bHistoryPrefersFollowUp
|
||||
? TEXT("closure_history_follow_up_continuation")
|
||||
: TEXT("closure_history_recommended_suppression");
|
||||
const EHyperTwistCoachFocusLane FocusLane = bHistoryPrefersFollowUp
|
||||
? EHyperTwistCoachFocusLane::Cadence
|
||||
: EHyperTwistCoachFocusLane::Stability;
|
||||
const FString Headline = bHistoryPrefersFollowUp
|
||||
? (bCurrentFollowUpContinuation
|
||||
? TEXT("Recovery history keeps follow-up continuity alive")
|
||||
: TEXT("Recovery history favors sustained follow-up continuity"))
|
||||
: (bCurrentBorderlineSuppression
|
||||
? TEXT("Recovery history suppresses borderline follow-up regeneration")
|
||||
: TEXT("Recovery history favors recommended consolidation over borderline follow-up"));
|
||||
const FString Detail = FString::Printf(
|
||||
TEXT("keepHistory=%d, suppressHistory=%d, currentClosure=%s, followUpReady=%d, recoverySource=%s"),
|
||||
SustainedHistoryCount,
|
||||
SuppressedHistoryCount,
|
||||
ClosureSummary.ClosureLabel.IsEmpty() ? TEXT("n/a") : *ClosureSummary.ClosureLabel,
|
||||
CoachMemorySnapshot.FollowUpReadyCoachSequenceCount,
|
||||
CoachMemorySnapshot.PreferredGuidanceSourceLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *CoachMemorySnapshot.PreferredGuidanceSourceLabel
|
||||
);
|
||||
const EHyperTwistTrainingDeliveryMode SuggestedMode = bHistoryPrefersFollowUp
|
||||
? EHyperTwistTrainingDeliveryMode::CoachReviewed
|
||||
: CoachMemorySnapshot.DominantCoachSuggestedMode;
|
||||
const EHyperTwistTrainingSelectionPolicy SuggestedSelectionPolicy = bHistoryPrefersFollowUp
|
||||
? EHyperTwistTrainingSelectionPolicy::Scripted
|
||||
: CoachMemorySnapshot.DominantCoachSelectionPolicy;
|
||||
|
||||
FHyperTwistCoachSignal Signal = HyperTwistTrainingCoachLibraryInternal::MakeSignal(
|
||||
SignalId,
|
||||
FocusLane,
|
||||
Score,
|
||||
Headline,
|
||||
Detail,
|
||||
SuggestedMode,
|
||||
SuggestedSelectionPolicy
|
||||
);
|
||||
Signal.SuggestedDeckId = !CurrentBrief.FocusDeckId.IsEmpty()
|
||||
? CurrentBrief.FocusDeckId
|
||||
: CoachMemorySnapshot.FocusDeckId;
|
||||
Signal.SuggestedMethodSegmentId = !CurrentBrief.FocusMethodSegmentId.IsEmpty()
|
||||
? CurrentBrief.FocusMethodSegmentId
|
||||
: CoachMemorySnapshot.FocusMethodSegmentId;
|
||||
Signal.SuggestedCaseIds = bHistoryPrefersFollowUp
|
||||
? (CoachMemorySnapshot.SchedulePressureCaseIds.Num() > 0
|
||||
? CoachMemorySnapshot.SchedulePressureCaseIds
|
||||
: CoachMemorySnapshot.PersistentCoachWeakCaseIds)
|
||||
: (CoachMemorySnapshot.RecurringCoachCaseIds.Num() > 0
|
||||
? CoachMemorySnapshot.RecurringCoachCaseIds
|
||||
: CoachMemorySnapshot.DueCaseIds);
|
||||
HyperTwistTrainingCoachLibraryInternal::ApplyGuidancePreferenceToSignal(
|
||||
Signal,
|
||||
bHistoryPrefersFollowUp
|
||||
? EHyperTwistTrainingCoachGuidanceLane::FollowUp
|
||||
: EHyperTwistTrainingCoachGuidanceLane::Recommended,
|
||||
CoachMemorySnapshot,
|
||||
bCompetingGuidancePressure
|
||||
);
|
||||
return Signal;
|
||||
}
|
||||
|
||||
FHyperTwistCoachBrief UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithClosureRecoveryHistorySignal(
|
||||
const FHyperTwistCoachBrief& BaseBrief,
|
||||
const FHyperTwistCoachSignal& ClosureRecoveryHistorySignal)
|
||||
{
|
||||
if (ClosureRecoveryHistorySignal.SignalId.IsEmpty())
|
||||
{
|
||||
return BaseBrief;
|
||||
}
|
||||
|
||||
FHyperTwistCoachBrief Brief = BaseBrief;
|
||||
if (!Brief.Signals.ContainsByPredicate(
|
||||
[&ClosureRecoveryHistorySignal](const FHyperTwistCoachSignal& Candidate)
|
||||
{
|
||||
return Candidate.SignalId == ClosureRecoveryHistorySignal.SignalId;
|
||||
}))
|
||||
{
|
||||
Brief.Signals.Add(ClosureRecoveryHistorySignal);
|
||||
}
|
||||
HyperTwistTrainingCoachLibraryInternal::SortSignals(Brief.Signals);
|
||||
|
||||
const bool bPolicyFacingBrief =
|
||||
Brief.FocusLane == EHyperTwistCoachFocusLane::Cadence
|
||||
|| Brief.FocusLane == EHyperTwistCoachFocusLane::Stability
|
||||
|| Brief.bNeedsCadenceRecovery;
|
||||
const bool bShouldPromoteHistorySignal =
|
||||
bPolicyFacingBrief
|
||||
&& ClosureRecoveryHistorySignal.Score >= Brief.PriorityScore - 5.0f;
|
||||
if (bShouldPromoteHistorySignal)
|
||||
{
|
||||
for (FHyperTwistCoachSignal& Signal : Brief.Signals)
|
||||
{
|
||||
if (Signal.SignalId == ClosureRecoveryHistorySignal.SignalId)
|
||||
{
|
||||
Signal.Score = FMath::Clamp(
|
||||
FMath::Max(Signal.Score, Brief.Signals[0].Score + 0.5f),
|
||||
0.0f,
|
||||
100.0f
|
||||
);
|
||||
Signal.Priority = HyperTwistTrainingCoachLibraryInternal::PriorityFromScore(Signal.Score);
|
||||
Signal.bNeedsImmediateAttention = Signal.Priority == EHyperTwistCoachPriority::Critical;
|
||||
break;
|
||||
}
|
||||
}
|
||||
HyperTwistTrainingCoachLibraryInternal::SortSignals(Brief.Signals);
|
||||
}
|
||||
|
||||
if (Brief.Signals.Num() > 0)
|
||||
{
|
||||
const FString OriginalDeckId = Brief.FocusDeckId;
|
||||
const FString OriginalMethodSegmentId = Brief.FocusMethodSegmentId;
|
||||
const TArray<FString> OriginalCaseIds = Brief.FocusCaseIds;
|
||||
HyperTwistTrainingCoachLibraryInternal::ApplyPrimarySignalToBrief(Brief, Brief.Signals[0]);
|
||||
if (Brief.FocusDeckId.IsEmpty())
|
||||
{
|
||||
Brief.FocusDeckId = OriginalDeckId;
|
||||
}
|
||||
if (Brief.FocusMethodSegmentId.IsEmpty())
|
||||
{
|
||||
Brief.FocusMethodSegmentId = OriginalMethodSegmentId;
|
||||
}
|
||||
if (Brief.FocusCaseIds.Num() <= 0)
|
||||
{
|
||||
Brief.FocusCaseIds = OriginalCaseIds;
|
||||
}
|
||||
}
|
||||
|
||||
return Brief;
|
||||
}
|
||||
|
||||
FHyperTwistCoachScheduleHorizonSummary UHyperTwistTrainingCoachLibrary::DeriveCoachScheduleHorizonSummary(
|
||||
const FHyperTwistTrainingCoachSessionQueueState& QueueState,
|
||||
const FHyperTwistTrainingCoachArchivePolicySummary& ArchivePolicySummary,
|
||||
|
|
|
|||
|
|
@ -2229,6 +2229,20 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
ActiveReplayReviewAnalytics,
|
||||
ActiveRecognitionReplaySummary
|
||||
);
|
||||
const FHyperTwistCoachSignal ClosureRecoveryHistorySignal =
|
||||
UHyperTwistTrainingCoachLibrary::DeriveClosureRecoveryHistorySignal(
|
||||
ActiveCoachActionClosureSummary,
|
||||
ActiveCoachMemorySnapshot,
|
||||
ActiveCoachBrief
|
||||
);
|
||||
if (!ClosureRecoveryHistorySignal.SignalId.IsEmpty())
|
||||
{
|
||||
ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithClosureRecoveryHistorySignal(
|
||||
ActiveCoachBrief,
|
||||
ClosureRecoveryHistorySignal
|
||||
);
|
||||
ActiveCoachSignals = ActiveCoachBrief.Signals;
|
||||
}
|
||||
ActiveCoachFollowUpBrief = ActiveCoachActionPlanOutcomeSummary.IsStructurallyValid()
|
||||
&& (
|
||||
ActiveCoachActionClosureSummary.bShouldSpawnFollowUp
|
||||
|
|
|
|||
|
|
@ -478,6 +478,19 @@ public:
|
|||
const FHyperTwistCoachSignal& QueueSuppressionSignal
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistCoachSignal DeriveClosureRecoveryHistorySignal(
|
||||
const FHyperTwistTrainingCoachActionClosureSummary& ClosureSummary,
|
||||
const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot,
|
||||
const FHyperTwistCoachBrief& CurrentBrief
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistCoachBrief RefineCoachBriefWithClosureRecoveryHistorySignal(
|
||||
const FHyperTwistCoachBrief& BaseBrief,
|
||||
const FHyperTwistCoachSignal& ClosureRecoveryHistorySignal
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistCoachScheduleHorizonSummary DeriveCoachScheduleHorizonSummary(
|
||||
const FHyperTwistTrainingCoachSessionQueueState& QueueState,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue