Persist drill follow-up packet structure outcomes upstream

This commit is contained in:
axiomlogicnexus 2026-04-29 16:43:54 +02:00
parent 789b065486
commit 88642bb9e6
4 changed files with 205 additions and 5 deletions

View file

@ -97,7 +97,8 @@ namespace HyperTwistTrainingCoachLibraryInternal
|| SourceLabel == TEXT("dashboard-handoff-method-drill-follow-up-packet-strong-queued")
|| SourceLabel == TEXT("dashboard-handoff-method-drill-follow-up-packet-strong-follow-up")
|| SourceLabel == TEXT("dashboard-handoff-method-drill-follow-up-packet-strong-recommended")
|| SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-strong");
|| SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-strong")
|| SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-structure-narrow");
}
bool IsWeakMethodDrillFollowUpPacketMemorySource(const FString& SourceLabel)
@ -106,7 +107,8 @@ namespace HyperTwistTrainingCoachLibraryInternal
|| SourceLabel == TEXT("dashboard-handoff-method-drill-follow-up-packet-weak-queued")
|| SourceLabel == TEXT("dashboard-handoff-method-drill-follow-up-packet-weak-follow-up")
|| SourceLabel == TEXT("dashboard-handoff-method-drill-follow-up-packet-weak-recommended")
|| SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-weak");
|| SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-weak")
|| SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-structure-broad");
}
bool IsStrongMethodDrillRecoveryMemorySource(const FString& SourceLabel)
@ -556,6 +558,10 @@ namespace HyperTwistTrainingCoachLibraryInternal
{
return TEXT("successful drill-follow-up-packet history");
}
if (SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-structure-narrow"))
{
return TEXT("successful narrow drill-follow-up-packet structure history");
}
if (SourceLabel == TEXT("coach-memory-dashboard-method-drill-follow-up-packet-strong-queued"))
{
return TEXT("successful queued drill-follow-up-packet history");
@ -576,6 +582,10 @@ namespace HyperTwistTrainingCoachLibraryInternal
{
return TEXT("weak drill-follow-up-packet history");
}
if (SourceLabel == TEXT("coach-memory-method-drill-follow-up-packet-structure-broad"))
{
return TEXT("successful broad drill-follow-up-packet redirect history");
}
if (SourceLabel == TEXT("coach-memory-dashboard-method-drill-follow-up-packet-weak-queued"))
{
return TEXT("weak queued drill-follow-up-packet history");
@ -753,7 +763,9 @@ namespace HyperTwistTrainingCoachLibraryInternal
CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-strong")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-strong");
== TEXT("coach-memory-method-drill-follow-up-packet-strong")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-structure-narrow");
const bool bPreferredHandoffSource =
CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
== TEXT("coach-memory-method-drill-follow-up-strong")
@ -792,7 +804,9 @@ namespace HyperTwistTrainingCoachLibraryInternal
CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-weak")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-weak");
== TEXT("coach-memory-method-drill-follow-up-packet-weak")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-structure-broad");
const bool bPreferredHandoffSource =
CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
== TEXT("coach-memory-method-drill-follow-up-weak")

View file

@ -448,6 +448,18 @@ namespace HyperTwistTrainingRepositoryLibraryInternal
&& TrainingSessionId.Contains(TEXT("method_drill_follow_up"), ESearchCase::IgnoreCase);
}
bool IsNarrowMethodDrillFollowUpPacketStructureSessionId(const FString& TrainingSessionId)
{
return !TrainingSessionId.IsEmpty()
&& TrainingSessionId.Contains(TEXT("__packet_narrow_"), ESearchCase::IgnoreCase);
}
bool IsBroadMethodDrillFollowUpPacketStructureSessionId(const FString& TrainingSessionId)
{
return !TrainingSessionId.IsEmpty()
&& TrainingSessionId.Contains(TEXT("__packet_broad_"), ESearchCase::IgnoreCase);
}
float ResolveMethodDrillFollowUpOutcomeScore(const FHyperTwistTrainingRunRecord& RunRecord)
{
if (!RunRecord.IsStructurallyValid())
@ -6651,6 +6663,8 @@ FHyperTwistTrainingCoachMemorySnapshot UHyperTwistTrainingRepositoryLibrary::Der
MethodDrillFollowUpRunRecords);
const int32 FirstRelevantIndex = FMath::Max(0, MethodDrillFollowUpRunRecords.Num() - 8);
float MethodDrillOutcomeAccumulator = 0.0f;
float NarrowMethodDrillPacketOutcomeAccumulator = 0.0f;
float BroadMethodDrillPacketOutcomeAccumulator = 0.0f;
for (int32 Index = FirstRelevantIndex; Index < MethodDrillFollowUpRunRecords.Num(); ++Index)
{
const FHyperTwistTrainingRunRecord& RunRecord = MethodDrillFollowUpRunRecords[Index];
@ -6659,6 +6673,18 @@ FHyperTwistTrainingCoachMemorySnapshot UHyperTwistTrainingRepositoryLibrary::Der
RunRecord);
Snapshot.MethodDrillFollowUpHistoryCount += 1;
MethodDrillOutcomeAccumulator += OutcomeScore;
if (HyperTwistTrainingRepositoryLibraryInternal::IsNarrowMethodDrillFollowUpPacketStructureSessionId(
RunRecord.Session.TrainingSessionId))
{
Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount += 1;
NarrowMethodDrillPacketOutcomeAccumulator += OutcomeScore;
}
else if (HyperTwistTrainingRepositoryLibraryInternal::IsBroadMethodDrillFollowUpPacketStructureSessionId(
RunRecord.Session.TrainingSessionId))
{
Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount += 1;
BroadMethodDrillPacketOutcomeAccumulator += OutcomeScore;
}
if (OutcomeScore >= 70.0f)
{
Snapshot.StrongMethodDrillFollowUpHistoryCount += 1;
@ -6675,6 +6701,18 @@ FHyperTwistTrainingCoachMemorySnapshot UHyperTwistTrainingRepositoryLibrary::Der
MethodDrillOutcomeAccumulator
/ static_cast<float>(Snapshot.MethodDrillFollowUpHistoryCount);
}
if (Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount > 0)
{
Snapshot.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore =
NarrowMethodDrillPacketOutcomeAccumulator
/ static_cast<float>(Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount);
}
if (Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount > 0)
{
Snapshot.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore =
BroadMethodDrillPacketOutcomeAccumulator
/ static_cast<float>(Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount);
}
const bool bStrongMethodDrillHistory =
Snapshot.MethodDrillFollowUpHistoryCount >= 2
@ -6720,6 +6758,67 @@ FHyperTwistTrainingCoachMemorySnapshot UHyperTwistTrainingRepositoryLibrary::Der
TEXT("coach-memory-method-drill-follow-up-strong");
}
}
const bool bNarrowMethodDrillPacketStructureHistory =
Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount >= 2
&& Snapshot.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore >= 60.0f
&& (Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount <= 0
|| Snapshot.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore
>= Snapshot.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore);
const bool bBroadMethodDrillPacketStructureHistory =
Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount >= 2
&& Snapshot.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore >= 58.0f
&& (Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount <= 0
|| Snapshot.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore
>= Snapshot.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore);
if (bNarrowMethodDrillPacketStructureHistory)
{
const int32 NarrowPacketStructureBias = FMath::Clamp(
Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount
- Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount
+ (Snapshot.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore >= 75.0f
? 1
: 0),
1,
3
);
Snapshot.FollowUpGuidanceContinueBias += NarrowPacketStructureBias;
Snapshot.SuppressedPrimaryQueuePressureCount += FMath::Max(
1,
NarrowPacketStructureBias - 1
);
if (Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::None
|| Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::Recommended
|| Snapshot.PreferredGuidanceSourceLabel.StartsWith(TEXT("recommendation-history"))
|| Snapshot.PreferredGuidanceSourceLabel.StartsWith(TEXT("coach-memory-method-drill")))
{
Snapshot.PreferredGuidanceLane = EHyperTwistTrainingCoachGuidanceLane::FollowUp;
Snapshot.PreferredGuidanceSourceLabel =
TEXT("coach-memory-method-drill-follow-up-packet-structure-narrow");
}
}
else if (bBroadMethodDrillPacketStructureHistory)
{
const int32 BroadPacketStructureBias = FMath::Clamp(
Snapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount
- Snapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount
+ (Snapshot.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore >= 72.0f
? 1
: 0),
1,
3
);
Snapshot.RecommendedGuidanceContinueBias += BroadPacketStructureBias;
Snapshot.SuppressedFollowUpQueuePressureCount += BroadPacketStructureBias;
if (Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::None
|| Snapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
|| Snapshot.PreferredGuidanceSourceLabel.StartsWith(TEXT("coach-memory-method-drill")))
{
Snapshot.PreferredGuidanceLane =
EHyperTwistTrainingCoachGuidanceLane::Recommended;
Snapshot.PreferredGuidanceSourceLabel =
TEXT("coach-memory-method-drill-follow-up-packet-structure-broad");
}
}
else if (bWeakMethodDrillHistory)
{
const int32 MethodDrillRedirectBias = FMath::Clamp(

View file

@ -225,6 +225,8 @@ namespace HyperTwistTrainingSubsystemInternal
== TEXT("coach-memory-method-drill-follow-up-strong")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-strong")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-structure-narrow")
|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
== TEXT("coach-memory-method-drill-follow-up-strong")
|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel.StartsWith(
@ -246,6 +248,8 @@ namespace HyperTwistTrainingSubsystemInternal
== TEXT("coach-memory-method-drill-follow-up-weak")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-weak")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-structure-broad")
|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
== TEXT("coach-memory-method-drill-follow-up-weak")
|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel.StartsWith(
@ -265,6 +269,8 @@ namespace HyperTwistTrainingSubsystemInternal
{
return CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-strong")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-structure-narrow")
|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel.StartsWith(
TEXT("coach-memory-dashboard-method-drill-follow-up-packet-strong-"));
}
@ -274,6 +280,8 @@ namespace HyperTwistTrainingSubsystemInternal
{
return CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-weak")
|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
== TEXT("coach-memory-method-drill-follow-up-packet-structure-broad")
|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel.StartsWith(
TEXT("coach-memory-dashboard-method-drill-follow-up-packet-weak-"));
}
@ -314,6 +322,42 @@ namespace HyperTwistTrainingSubsystemInternal
}
}
FString ResolveMethodDrillFollowUpPacketStructureToken(
const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
{
const bool bStrongMethodDrillPacketMemory = IsStrongMethodDrillFollowUpPacketMemory(
CoachMemorySnapshot
);
const bool bWeakMethodDrillPacketMemory = IsWeakMethodDrillFollowUpPacketMemory(
CoachMemorySnapshot
);
const EHyperTwistTrainingCoachHandoffKind PacketHandoffKind =
MethodDrillFollowUpPacketHandoffKindFromSourceLabel(
CoachMemorySnapshot.PreferredCoachHandoffSourceLabel,
CoachMemorySnapshot.PreferredCoachHandoffKind);
if (bStrongMethodDrillPacketMemory && !bWeakMethodDrillPacketMemory)
{
switch (PacketHandoffKind)
{
case EHyperTwistTrainingCoachHandoffKind::Queue:
return TEXT("packet_narrow_queue_entry_first");
case EHyperTwistTrainingCoachHandoffKind::Recommended:
return TEXT("packet_narrow_recommended_brief_first");
case EHyperTwistTrainingCoachHandoffKind::FollowUp:
default:
return TEXT("packet_narrow_follow_up_packet_first");
}
}
if (bWeakMethodDrillPacketMemory && !bStrongMethodDrillPacketMemory)
{
return PacketHandoffKind == EHyperTwistTrainingCoachHandoffKind::Recommended
? TEXT("packet_broad_recommended_brief_redirect")
: TEXT("packet_broad_broadened_redirect_first");
}
return FString();
}
FHyperTwistTrainingSessionTemplate ApplyMethodDrillFollowUpMemoryBias(
const FHyperTwistTrainingSessionTemplate& SessionTemplate,
const FHyperTwistTrainingMethodDrillDiagnosticPacket& DiagnosticPacket,
@ -715,6 +759,14 @@ FHyperTwistTrainingCoachPanelState UHyperTwistTrainingSubsystem::GetActiveCoachP
ActiveCoachMemorySnapshot.WeakMethodDrillFollowUpHistoryCount;
PanelState.MethodDrillFollowUpAverageOutcomeScore =
ActiveCoachMemorySnapshot.MethodDrillFollowUpAverageOutcomeScore;
PanelState.NarrowMethodDrillFollowUpPacketStructureHistoryCount =
ActiveCoachMemorySnapshot.NarrowMethodDrillFollowUpPacketStructureHistoryCount;
PanelState.BroadMethodDrillFollowUpPacketStructureHistoryCount =
ActiveCoachMemorySnapshot.BroadMethodDrillFollowUpPacketStructureHistoryCount;
PanelState.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore =
ActiveCoachMemorySnapshot.NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore;
PanelState.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore =
ActiveCoachMemorySnapshot.BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore;
PanelState.MethodDrillRecoveryHistoryCount =
ActiveCoachMemorySnapshot.MethodDrillRecoveryHistoryCount;
PanelState.StrongMethodDrillRecoveryHistoryCount =
@ -1868,10 +1920,21 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartActiveMethodDrill
const FString ResolvedSessionId = !SessionId.IsEmpty()
? SessionId
: FString::Printf(TEXT("method_drill_follow_up_%s"), *ActiveMethodDrillRunState.RunId);
const FString MethodDrillPacketStructureToken =
SessionId.IsEmpty()
? HyperTwistTrainingSubsystemInternal::ResolveMethodDrillFollowUpPacketStructureToken(
ActiveCoachMemorySnapshot)
: FString();
const FString StructuredSessionId = !MethodDrillPacketStructureToken.IsEmpty()
? FString::Printf(
TEXT("%s__%s"),
*ResolvedSessionId,
*MethodDrillPacketStructureToken)
: ResolvedSessionId;
return StartTrainingRunFromDeck(
FollowUpDeck,
ActiveMethodDrillRunState.UserId,
ResolvedSessionId,
StructuredSessionId,
ActiveMethodDrillFollowUpTemplate.SuggestedMode
);
}

View file

@ -1935,6 +1935,18 @@ struct FHyperTwistTrainingCoachMemorySnapshot
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float MethodDrillFollowUpAverageOutcomeScore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 NarrowMethodDrillFollowUpPacketStructureHistoryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 BroadMethodDrillFollowUpPacketStructureHistoryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MethodDrillRecoveryHistoryCount = 0;
@ -4912,6 +4924,18 @@ struct FHyperTwistTrainingCoachPanelState
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float MethodDrillFollowUpAverageOutcomeScore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 NarrowMethodDrillFollowUpPacketStructureHistoryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 BroadMethodDrillFollowUpPacketStructureHistoryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float NarrowMethodDrillFollowUpPacketStructureAverageOutcomeScore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float BroadMethodDrillFollowUpPacketStructureAverageOutcomeScore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MethodDrillRecoveryHistoryCount = 0;