Preserve coach state through run clear
This commit is contained in:
parent
69290897de
commit
c7e02fe1cd
3 changed files with 403 additions and 106 deletions
|
|
@ -3073,7 +3073,13 @@ bool UHyperTwistTrainingSubsystem::TryMaterializeTrainingSessionTemplateForUser(
|
|||
|
||||
FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveReviewDeck(int32 MaxCases) const
|
||||
{
|
||||
if (!ActiveRunState.ActiveDeck.IsStructurallyValid())
|
||||
if (!HasActiveRun())
|
||||
{
|
||||
return FHyperTwistTrainingDeck();
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingDeck SourceDeck = ResolveRepositoryFocusDeck();
|
||||
if (!SourceDeck.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingDeck();
|
||||
}
|
||||
|
|
@ -3092,7 +3098,7 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveReviewDeck(int3
|
|||
);
|
||||
|
||||
return UHyperTwistTrainingRepositoryLibrary::BuildReviewDeckFromRecommendations(
|
||||
ActiveRunState.ActiveDeck,
|
||||
SourceDeck,
|
||||
FilteredRecommendations,
|
||||
MaxCases
|
||||
);
|
||||
|
|
@ -3100,7 +3106,8 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveReviewDeck(int3
|
|||
|
||||
FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachRecommendedDeck(int32 MaxCases) const
|
||||
{
|
||||
if (!ActiveRunState.ActiveDeck.IsStructurallyValid())
|
||||
const FHyperTwistTrainingDeck SourceDeck = ResolveRepositoryFocusDeck();
|
||||
if (!SourceDeck.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingDeck();
|
||||
}
|
||||
|
|
@ -3115,7 +3122,7 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachRecommende
|
|||
TArray<FHyperTwistTrainingCase> FocusCases;
|
||||
for (const FString& FocusCaseId : ActiveCoachBrief.FocusCaseIds)
|
||||
{
|
||||
const FHyperTwistTrainingCase* MatchingCase = ActiveRunState.ActiveDeck.Cases.FindByPredicate(
|
||||
const FHyperTwistTrainingCase* MatchingCase = SourceDeck.Cases.FindByPredicate(
|
||||
[&FocusCaseId](const FHyperTwistTrainingCase& Candidate)
|
||||
{
|
||||
return Candidate.CaseId == FocusCaseId;
|
||||
|
|
@ -3133,13 +3140,16 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachRecommende
|
|||
|
||||
if (FocusCases.Num() == 0)
|
||||
{
|
||||
const FHyperTwistTrainingDeck ReviewDeck = BuildActiveReviewDeck(ResolvedBudget.ResolvedCaseCount);
|
||||
if (ReviewDeck.IsStructurallyValid())
|
||||
if (HasActiveRun())
|
||||
{
|
||||
return ReviewDeck;
|
||||
const FHyperTwistTrainingDeck ReviewDeck = BuildActiveReviewDeck(ResolvedBudget.ResolvedCaseCount);
|
||||
if (ReviewDeck.IsStructurallyValid())
|
||||
{
|
||||
return ReviewDeck;
|
||||
}
|
||||
}
|
||||
|
||||
for (const FHyperTwistTrainingCase& Candidate : ActiveRunState.ActiveDeck.Cases)
|
||||
for (const FHyperTwistTrainingCase& Candidate : SourceDeck.Cases)
|
||||
{
|
||||
FocusCases.Add(Candidate);
|
||||
if (FocusCases.Num() >= ResolvedBudget.ResolvedCaseCount)
|
||||
|
|
@ -3154,7 +3164,7 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachRecommende
|
|||
return FHyperTwistTrainingDeck();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingDeck FocusDeck = ActiveRunState.ActiveDeck;
|
||||
FHyperTwistTrainingDeck FocusDeck = SourceDeck;
|
||||
FocusDeck.Cases = FocusCases;
|
||||
FocusDeck.SelectionPolicy = ActiveCoachBrief.SuggestedSelectionPolicy;
|
||||
if (ActiveCoachBrief.SuggestedMode != EHyperTwistTrainingDeliveryMode::Timer
|
||||
|
|
@ -3180,7 +3190,8 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachRecommende
|
|||
|
||||
FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachFollowUpDeck(int32 MaxCases) const
|
||||
{
|
||||
if (!ActiveRunState.ActiveDeck.IsStructurallyValid() || ActiveCoachFollowUpBrief.UserId.IsEmpty())
|
||||
const FHyperTwistTrainingDeck SourceDeck = ResolveRepositoryFocusDeck();
|
||||
if (!SourceDeck.IsStructurallyValid() || ActiveCoachFollowUpBrief.UserId.IsEmpty())
|
||||
{
|
||||
return FHyperTwistTrainingDeck();
|
||||
}
|
||||
|
|
@ -3195,7 +3206,7 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachFollowUpDe
|
|||
TArray<FHyperTwistTrainingCase> FocusCases;
|
||||
for (const FString& FocusCaseId : ActiveCoachFollowUpBrief.FocusCaseIds)
|
||||
{
|
||||
const FHyperTwistTrainingCase* MatchingCase = ActiveRunState.ActiveDeck.Cases.FindByPredicate(
|
||||
const FHyperTwistTrainingCase* MatchingCase = SourceDeck.Cases.FindByPredicate(
|
||||
[&FocusCaseId](const FHyperTwistTrainingCase& Candidate)
|
||||
{
|
||||
return Candidate.CaseId == FocusCaseId;
|
||||
|
|
@ -3216,7 +3227,7 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachFollowUpDe
|
|||
return BuildActiveCoachRecommendedDeck(ResolvedBudget.ResolvedCaseCount);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingDeck FocusDeck = ActiveRunState.ActiveDeck;
|
||||
FHyperTwistTrainingDeck FocusDeck = SourceDeck;
|
||||
FocusDeck.Cases = FocusCases;
|
||||
FocusDeck.SelectionPolicy = ActiveCoachFollowUpBrief.SuggestedSelectionPolicy;
|
||||
if (ActiveCoachFollowUpBrief.SuggestedMode != EHyperTwistTrainingDeliveryMode::Timer
|
||||
|
|
@ -3813,6 +3824,9 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromDe
|
|||
ActiveCoachActionPlan = FHyperTwistTrainingCoachActionPlan();
|
||||
ActiveCoachFollowUpBrief = FHyperTwistCoachBrief();
|
||||
ActiveImportedGeneratedModeLaunchRequest = FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
|
||||
RetainedRepositoryViewUserId.Reset();
|
||||
RetainedRepositoryViewDeckId.Reset();
|
||||
RetainedRepositoryViewReferenceUtc.Reset();
|
||||
ActiveRunState = UHyperTwistTrainingLibrary::StartTrainingRun(Deck, UserId, SessionId, Mode);
|
||||
ActiveRunState.ImportedGeneratedModeLaunchRequest = ActiveImportedGeneratedModeLaunchRequest;
|
||||
bHasActiveRun = ActiveRunState.IsStructurallyValid();
|
||||
|
|
@ -4144,6 +4158,31 @@ void UHyperTwistTrainingSubsystem::ClearActiveRun()
|
|||
FString CloseError;
|
||||
CloseActiveRecognitionSession(CloseError);
|
||||
}
|
||||
RetainedRepositoryViewUserId = !ActiveRunState.Session.UserId.IsEmpty()
|
||||
? ActiveRunState.Session.UserId
|
||||
: (!ActiveCoachBrief.UserId.IsEmpty() ? ActiveCoachBrief.UserId : ActiveCoachSessionQueueSummary.UserId);
|
||||
RetainedRepositoryViewDeckId = !ActiveReviewProgramSummary.FocusDeckId.IsEmpty()
|
||||
? ActiveReviewProgramSummary.FocusDeckId
|
||||
: (!ActiveCoachBrief.FocusDeckId.IsEmpty()
|
||||
? ActiveCoachBrief.FocusDeckId
|
||||
: (!ActiveCoachFollowUpBrief.FocusDeckId.IsEmpty()
|
||||
? ActiveCoachFollowUpBrief.FocusDeckId
|
||||
: (!ActiveCoachSessionQueueState.FocusDeckId.IsEmpty()
|
||||
? ActiveCoachSessionQueueState.FocusDeckId
|
||||
: (!ActiveCoachSessionQueueSummary.FocusDeckId.IsEmpty()
|
||||
? ActiveCoachSessionQueueSummary.FocusDeckId
|
||||
: (!ActiveCoachMemorySnapshot.FocusDeckId.IsEmpty()
|
||||
? ActiveCoachMemorySnapshot.FocusDeckId
|
||||
: ActiveRunState.Session.DeckId)))));
|
||||
RetainedRepositoryViewReferenceUtc = !ActiveLearnerDeckStateSummary.ReferenceUtc.IsEmpty()
|
||||
? ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
: (!ActiveReviewProgramSummary.ReferenceUtc.IsEmpty()
|
||||
? ActiveReviewProgramSummary.ReferenceUtc
|
||||
: (!ActiveCoachMemorySnapshot.ReferenceUtc.IsEmpty()
|
||||
? ActiveCoachMemorySnapshot.ReferenceUtc
|
||||
: (!ActiveRunSummary.LastCompletedAtUtc.IsEmpty()
|
||||
? ActiveRunSummary.LastCompletedAtUtc
|
||||
: FDateTime::UtcNow().ToIso8601())));
|
||||
ActiveRunState = FHyperTwistTrainingRunState();
|
||||
ActiveRunSummary = FHyperTwistTrainingSessionSummary();
|
||||
ActiveImportedGeneratedModeLaunchRequest = FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
|
||||
|
|
@ -4781,6 +4820,83 @@ void UHyperTwistTrainingSubsystem::ResetRecognitionSessionState()
|
|||
RefreshRecognitionServiceHealth();
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::TryResolveRepositoryViewContext(
|
||||
FString& OutUserId,
|
||||
FString& OutDeckId,
|
||||
FString& OutReferenceUtc
|
||||
) const
|
||||
{
|
||||
OutUserId.Reset();
|
||||
OutDeckId.Reset();
|
||||
OutReferenceUtc.Reset();
|
||||
|
||||
if (ActiveRunState.Session.IsStructurallyValid())
|
||||
{
|
||||
OutUserId = ActiveRunState.Session.UserId;
|
||||
OutDeckId = ActiveRunState.Session.DeckId;
|
||||
OutReferenceUtc = !ActiveLearnerDeckStateSummary.ReferenceUtc.IsEmpty()
|
||||
? ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
: (!ActiveRunSummary.LastCompletedAtUtc.IsEmpty()
|
||||
? ActiveRunSummary.LastCompletedAtUtc
|
||||
: FDateTime::UtcNow().ToIso8601());
|
||||
return !OutUserId.IsEmpty();
|
||||
}
|
||||
|
||||
if (RetainedRepositoryViewUserId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutUserId = RetainedRepositoryViewUserId;
|
||||
OutDeckId = RetainedRepositoryViewDeckId;
|
||||
OutReferenceUtc = !RetainedRepositoryViewReferenceUtc.IsEmpty()
|
||||
? RetainedRepositoryViewReferenceUtc
|
||||
: FDateTime::UtcNow().ToIso8601();
|
||||
return true;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::ResolveRepositoryFocusDeck() const
|
||||
{
|
||||
if (ActiveRunState.ActiveDeck.IsStructurallyValid())
|
||||
{
|
||||
return ActiveRunState.ActiveDeck;
|
||||
}
|
||||
|
||||
TArray<FString> CandidateDeckIds;
|
||||
CandidateDeckIds.Reserve(8);
|
||||
const auto AddCandidateDeckId = [&CandidateDeckIds](const FString& CandidateDeckId)
|
||||
{
|
||||
if (!CandidateDeckId.IsEmpty())
|
||||
{
|
||||
CandidateDeckIds.AddUnique(CandidateDeckId);
|
||||
}
|
||||
};
|
||||
|
||||
AddCandidateDeckId(ActiveCoachBrief.FocusDeckId);
|
||||
AddCandidateDeckId(ActiveCoachFollowUpBrief.FocusDeckId);
|
||||
AddCandidateDeckId(ActiveReviewProgramSummary.FocusDeckId);
|
||||
AddCandidateDeckId(ActiveCoachSessionQueueState.FocusDeckId);
|
||||
AddCandidateDeckId(ActiveCoachSessionQueueSummary.FocusDeckId);
|
||||
AddCandidateDeckId(ActiveCoachMemorySnapshot.FocusDeckId);
|
||||
AddCandidateDeckId(RetainedRepositoryViewDeckId);
|
||||
AddCandidateDeckId(ActiveLearnerProfile.FavoriteDeckId);
|
||||
|
||||
const TArray<FHyperTwistContentPack> TrainingCatalog = UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog();
|
||||
FHyperTwistTrainingDeck SourceDeck;
|
||||
for (const FString& CandidateDeckId : CandidateDeckIds)
|
||||
{
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryFindDeckInCatalog(
|
||||
TrainingCatalog,
|
||||
CandidateDeckId,
|
||||
SourceDeck))
|
||||
{
|
||||
return SourceDeck;
|
||||
}
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingDeck();
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::RefreshSummary()
|
||||
{
|
||||
if (!ActiveRunState.Session.IsStructurallyValid())
|
||||
|
|
@ -4831,7 +4947,13 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
);
|
||||
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RepairRepositoryState(TrainingRepositoryState);
|
||||
|
||||
if (!ActiveRunState.Session.IsStructurallyValid())
|
||||
FString RepositoryViewUserId;
|
||||
FString RepositoryViewDeckId;
|
||||
FString RepositoryViewReferenceUtc;
|
||||
if (!TryResolveRepositoryViewContext(
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewDeckId,
|
||||
RepositoryViewReferenceUtc))
|
||||
{
|
||||
ActiveDeckHistorySummary = FHyperTwistTrainingDeckHistorySummary();
|
||||
ActiveTimingTrendSummary = FHyperTwistTrainingTimingTrendSummary();
|
||||
|
|
@ -4869,140 +4991,196 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
return;
|
||||
}
|
||||
|
||||
ActiveDeckHistorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveDeckHistorySummary(
|
||||
const bool bHasActiveRunContext = ActiveRunState.Session.IsStructurallyValid();
|
||||
|
||||
ActiveLearnerProfile = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerProfile(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveRunState.Session.DeckId
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
ActiveTimingTrendSummary = UHyperTwistTrainingRepositoryLibrary::DeriveTimingTrendSummary(
|
||||
ActiveCoachMemorySnapshot = UHyperTwistTrainingRepositoryLibrary::DeriveCoachMemorySnapshot(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveRunState.Session.DeckId,
|
||||
FString()
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
ActivePersonalBestSummary = UHyperTwistTrainingRepositoryLibrary::DerivePersonalBestSummary(
|
||||
ActiveCoachClosureMemorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachClosureMemorySummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveRunState.Session.DeckId,
|
||||
ActiveTimingTrendSummary.ReferenceUtc
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
ActiveDeckScopedStats = UHyperTwistTrainingRepositoryLibrary::DeriveDeckScopedStats(
|
||||
ActiveCoachRecommendationHistorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachRecommendationHistorySummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveRunState.Session.DeckId,
|
||||
FString()
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
const FString CurrentCaseId = ActiveRunState.CurrentSelection.IsStructurallyValid()
|
||||
? ActiveRunState.CurrentSelection.TrainingCase.CaseId
|
||||
: ActiveRunState.Session.CurrentCaseId;
|
||||
ActiveCurrentCaseScopedStats = !CurrentCaseId.IsEmpty()
|
||||
ActiveCoachCarryForwardPolicySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachCarryForwardPolicySummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
ActiveCoachArchivePolicySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachArchivePolicySummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
ActiveReviewProgramSummary = UHyperTwistTrainingRepositoryLibrary::DeriveReviewProgramSummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
RepositoryViewReferenceUtc
|
||||
);
|
||||
|
||||
const FString ResolvedDeckId = bHasActiveRunContext
|
||||
? ActiveRunState.Session.DeckId
|
||||
: (!ActiveReviewProgramSummary.FocusDeckId.IsEmpty()
|
||||
? ActiveReviewProgramSummary.FocusDeckId
|
||||
: (!ActiveCoachMemorySnapshot.FocusDeckId.IsEmpty()
|
||||
? ActiveCoachMemorySnapshot.FocusDeckId
|
||||
: (!RepositoryViewDeckId.IsEmpty()
|
||||
? RepositoryViewDeckId
|
||||
: ActiveLearnerProfile.FavoriteDeckId)));
|
||||
FHyperTwistTrainingDeck RepositoryFocusDeck = bHasActiveRunContext
|
||||
? ActiveRunState.ActiveDeck
|
||||
: FHyperTwistTrainingDeck();
|
||||
if (!RepositoryFocusDeck.IsStructurallyValid())
|
||||
{
|
||||
RepositoryFocusDeck = ResolveRepositoryFocusDeck();
|
||||
}
|
||||
if (!RepositoryFocusDeck.IsStructurallyValid() && !ResolvedDeckId.IsEmpty())
|
||||
{
|
||||
UHyperTwistTrainingCatalogLibrary::TryFindDeckInCatalog(
|
||||
UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog(),
|
||||
ResolvedDeckId,
|
||||
RepositoryFocusDeck
|
||||
);
|
||||
}
|
||||
|
||||
ActiveDeckHistorySummary = !ResolvedDeckId.IsEmpty()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveDeckHistorySummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
ResolvedDeckId
|
||||
)
|
||||
: FHyperTwistTrainingDeckHistorySummary();
|
||||
ActiveTimingTrendSummary = !ResolvedDeckId.IsEmpty()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveTimingTrendSummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
ResolvedDeckId,
|
||||
FString()
|
||||
)
|
||||
: FHyperTwistTrainingTimingTrendSummary();
|
||||
ActivePersonalBestSummary = !ResolvedDeckId.IsEmpty()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DerivePersonalBestSummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
ResolvedDeckId,
|
||||
ActiveTimingTrendSummary.ReferenceUtc
|
||||
)
|
||||
: FHyperTwistTrainingPersonalBestSummary();
|
||||
ActiveDeckScopedStats = !ResolvedDeckId.IsEmpty()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveDeckScopedStats(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
ResolvedDeckId,
|
||||
FString()
|
||||
)
|
||||
: FHyperTwistTrainingDeckScopedStats();
|
||||
const FString CurrentCaseId = bHasActiveRunContext
|
||||
? (ActiveRunState.CurrentSelection.IsStructurallyValid()
|
||||
? ActiveRunState.CurrentSelection.TrainingCase.CaseId
|
||||
: ActiveRunState.Session.CurrentCaseId)
|
||||
: FString();
|
||||
ActiveCurrentCaseScopedStats = (!ResolvedDeckId.IsEmpty() && !CurrentCaseId.IsEmpty())
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveCaseScopedStats(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveRunState.Session.DeckId,
|
||||
RepositoryViewUserId,
|
||||
ResolvedDeckId,
|
||||
CurrentCaseId,
|
||||
ActiveDeckScopedStats.ReferenceUtc
|
||||
)
|
||||
: FHyperTwistTrainingCaseScopedStats();
|
||||
ActiveLearnerDeckStateSummary = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerDeckStateSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveRunState.Session.DeckId,
|
||||
FString()
|
||||
);
|
||||
ActiveLearnerProfile = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerProfile(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCoachMemorySnapshot = UHyperTwistTrainingRepositoryLibrary::DeriveCoachMemorySnapshot(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCoachClosureMemorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachClosureMemorySummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCoachRecommendationHistorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachRecommendationHistorySummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCoachCarryForwardPolicySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachCarryForwardPolicySummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCoachArchivePolicySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachArchivePolicySummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveReplayReviewAnalytics = UHyperTwistReplayReviewLibrary::DeriveReplayReviewAnalytics(
|
||||
ActiveRunState.ReplayPacket
|
||||
);
|
||||
ActiveRecognitionReplaySummary = UHyperTwistRecognitionReplayLibrary::DeriveRecognitionReplaySummary(
|
||||
ActiveRunState.ReplayPacket
|
||||
);
|
||||
ActiveLearnerDeckStateSummary = !ResolvedDeckId.IsEmpty()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveLearnerDeckStateSummary(
|
||||
TrainingRepositoryState,
|
||||
RepositoryViewUserId,
|
||||
ResolvedDeckId,
|
||||
FString()
|
||||
)
|
||||
: FHyperTwistTrainingLearnerDeckStateSummary();
|
||||
const FString ResolvedReferenceUtc = !ActiveLearnerDeckStateSummary.ReferenceUtc.IsEmpty()
|
||||
? ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
: RepositoryViewReferenceUtc;
|
||||
ActiveReplayReviewAnalytics = bHasActiveRunContext
|
||||
? UHyperTwistReplayReviewLibrary::DeriveReplayReviewAnalytics(ActiveRunState.ReplayPacket)
|
||||
: FHyperTwistReplayReviewAnalytics();
|
||||
ActiveRecognitionReplaySummary = bHasActiveRunContext
|
||||
? UHyperTwistRecognitionReplayLibrary::DeriveRecognitionReplaySummary(ActiveRunState.ReplayPacket)
|
||||
: FHyperTwistRecognitionReplaySummary();
|
||||
ActiveLearnerMethodSegments = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerMethodSegments(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
RepositoryViewUserId,
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
ActiveLearnerPresets = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerPresets(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
RepositoryViewUserId,
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
ActiveTrainingSessionTemplates = BuildTrainingSessionTemplatesForUser(
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCaseRecommendations = UHyperTwistTrainingRepositoryLibrary::ListCaseRecommendationsForDeck(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.ActiveDeck,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc,
|
||||
5
|
||||
RepositoryViewUserId,
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
ActiveCaseRecommendations = RepositoryFocusDeck.IsStructurallyValid()
|
||||
? UHyperTwistTrainingRepositoryLibrary::ListCaseRecommendationsForDeck(
|
||||
TrainingRepositoryState,
|
||||
RepositoryFocusDeck,
|
||||
RepositoryViewUserId,
|
||||
ResolvedReferenceUtc,
|
||||
5
|
||||
)
|
||||
: TArray<FHyperTwistTrainingCaseRecommendation>();
|
||||
ActiveReviewFlowStatus = ActiveReviewPlanState.IsStructurallyValid()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(ActiveReviewPlanState)
|
||||
: FHyperTwistTrainingReviewFlowStatus();
|
||||
ActiveReviewProgramSummary = UHyperTwistTrainingRepositoryLibrary::DeriveReviewProgramSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
);
|
||||
ActiveCoachActionPlanSummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionPlanSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState.Session.UserId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
RepositoryViewUserId,
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
ActiveCoachActionPlanOutcomeSummary = ActiveCoachActionPlan.IsStructurallyValid()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionPlanOutcomeSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveCoachActionPlan,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
)
|
||||
: FHyperTwistTrainingCoachActionPlanOutcomeSummary();
|
||||
ActiveCoachActionSequenceSummary = ActiveCoachActionPlan.IsStructurallyValid()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionSequenceSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveCoachActionPlan,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
)
|
||||
: FHyperTwistTrainingCoachActionSequenceSummary();
|
||||
ActiveCoachActionClosureSummary = ActiveCoachActionPlan.IsStructurallyValid()
|
||||
? UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionClosureSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveCoachActionPlan,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
)
|
||||
: FHyperTwistTrainingCoachActionClosureSummary();
|
||||
FHyperTwistTrainingSessionSummary RepositoryViewSessionSummary = bHasActiveRunContext
|
||||
? ActiveRunSummary
|
||||
: FHyperTwistTrainingSessionSummary();
|
||||
if (RepositoryViewSessionSummary.UserId.IsEmpty())
|
||||
{
|
||||
RepositoryViewSessionSummary.UserId = RepositoryViewUserId;
|
||||
}
|
||||
if (RepositoryViewSessionSummary.DeckId.IsEmpty())
|
||||
{
|
||||
RepositoryViewSessionSummary.DeckId = ResolvedDeckId;
|
||||
}
|
||||
ActiveCoachSignals = UHyperTwistTrainingCoachLibrary::DeriveCoachSignals(
|
||||
ActiveRunSummary,
|
||||
RepositoryViewSessionSummary,
|
||||
ActiveDeckScopedStats,
|
||||
ActiveLearnerDeckStateSummary,
|
||||
ActiveLearnerProfile,
|
||||
|
|
@ -5012,7 +5190,7 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
ActiveRecognitionReplaySummary
|
||||
);
|
||||
ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::DeriveCoachBrief(
|
||||
ActiveRunSummary,
|
||||
RepositoryViewSessionSummary,
|
||||
ActiveDeckScopedStats,
|
||||
ActiveLearnerDeckStateSummary,
|
||||
ActiveLearnerProfile,
|
||||
|
|
@ -5087,12 +5265,12 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
? UHyperTwistTrainingRepositoryLibrary::ResolveCoachSessionQueueState(
|
||||
StoredQueueState,
|
||||
ActiveCoachSessionQueueSummary,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
)
|
||||
: UHyperTwistTrainingRepositoryLibrary::BuildCoachSessionQueueState(
|
||||
ActiveCoachSessionQueueSummary,
|
||||
HyperTwistTrainingSubsystemInternal::ActiveCoachSessionQueueId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
if (ActiveCoachSessionQueueState.IsStructurallyValid())
|
||||
{
|
||||
|
|
@ -5104,7 +5282,7 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
ActiveCoachScheduleHorizonSummary = UHyperTwistTrainingCoachLibrary::DeriveCoachScheduleHorizonSummary(
|
||||
ActiveCoachSessionQueueState,
|
||||
ActiveCoachArchivePolicySummary,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
ActiveCoachSchedulePolicySummary = UHyperTwistTrainingCoachLibrary::DeriveCoachSchedulePolicySummary(
|
||||
ActiveCoachSessionQueueState,
|
||||
|
|
@ -5112,14 +5290,14 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
|||
ActiveCoachActionClosureSummary,
|
||||
ActiveCoachMemorySnapshot,
|
||||
ActiveCoachArchivePolicySummary,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
ActiveCoachSessionQueueExecutionSummary =
|
||||
UHyperTwistTrainingRepositoryLibrary::DeriveCoachSessionQueueExecutionSummary(
|
||||
TrainingRepositoryState,
|
||||
ActiveCoachSessionQueueState.UserId,
|
||||
ActiveCoachSessionQueueState.QueueId,
|
||||
ActiveLearnerDeckStateSummary.ReferenceUtc
|
||||
ResolvedReferenceUtc
|
||||
);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -578,6 +578,12 @@ private:
|
|||
const FString& UserId,
|
||||
const FString& ReferenceUtc
|
||||
) const;
|
||||
bool TryResolveRepositoryViewContext(
|
||||
FString& OutUserId,
|
||||
FString& OutDeckId,
|
||||
FString& OutReferenceUtc
|
||||
) const;
|
||||
FHyperTwistTrainingDeck ResolveRepositoryFocusDeck() const;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingRunState ActiveRunState;
|
||||
|
|
@ -585,6 +591,15 @@ private:
|
|||
UPROPERTY()
|
||||
FHyperTwistTrainingSessionSummary ActiveRunSummary;
|
||||
|
||||
UPROPERTY()
|
||||
FString RetainedRepositoryViewUserId;
|
||||
|
||||
UPROPERTY()
|
||||
FString RetainedRepositoryViewDeckId;
|
||||
|
||||
UPROPERTY()
|
||||
FString RetainedRepositoryViewReferenceUtc;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingImportedGeneratedModeLaunchRequest ActiveImportedGeneratedModeLaunchRequest;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
# HyperTwist Phase 4 clear-run repository-view continuity packet
|
||||
|
||||
Created on `2026-05-06`
|
||||
|
||||
Status:
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- bounded Phase `4` coach-to-review validation slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet closes the next post-review continuity gap in the live recognition-assisted coach-to-review loop.
|
||||
|
||||
The open task is:
|
||||
|
||||
- preserve repository-derived carryover pressure, coach guidance, and queue state across `ClearActiveRun()` after a review run has already finalized truthfully
|
||||
|
||||
It is not:
|
||||
|
||||
- a new review-policy heuristic packet
|
||||
- a new recognition transport packet
|
||||
- a new queue-model redesign
|
||||
- a dashboard layout packet
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- retain the minimum repository-view context needed after a run clears
|
||||
- rebuild repository-derived coach and queue state from that retained context when no run is active
|
||||
- keep active review-plan inspection cleared so the dashboard does not imply a run is still open
|
||||
- let post-run coach launch surfaces resolve their focus deck from repository state instead of requiring a live run deck
|
||||
|
||||
Out of scope:
|
||||
|
||||
- new review scoring
|
||||
- new persistence formats
|
||||
- startup-wide multi-user queue arbitration
|
||||
- broader subsystem decomposition
|
||||
|
||||
## Why this was the right next packet
|
||||
|
||||
Before this slice:
|
||||
|
||||
- review-start summary continuity was already landed
|
||||
- review-finalization carryover continuity was already landed
|
||||
- post-review carryover could survive explicit review-run completion inside repository state
|
||||
|
||||
But one clear-run seam was still wrong:
|
||||
|
||||
- `ClearActiveRun()` reset the live run state and then called `RefreshRepositoryViews()`
|
||||
- `RefreshRepositoryViews()` treated `!ActiveRunState.Session.IsStructurallyValid()` as a full reset boundary
|
||||
- that zeroed repository-derived coach brief, queue summary, learner deck summary, review-program summary, and dashboard-facing carryover pressure
|
||||
|
||||
That meant the product could preserve open review carryover in the repository and still lose it immediately in the coach/dashboard lane as soon as the run was cleared.
|
||||
|
||||
The practical consequence was:
|
||||
|
||||
- queue-backed follow-up pressure could disappear right after run clear
|
||||
- post-review coach guidance could collapse to idle state even though carryover still existed
|
||||
- dashboard inspection could look clean only because the repository-derived view had been zeroed, not because the review program was actually resolved
|
||||
|
||||
So the next honest move was:
|
||||
|
||||
- keep the active review plan cleared, but stop discarding valid repository-derived coach and queue state at the clear-run boundary
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSubsystem.h`
|
||||
- added retained repository-view user/deck/reference fields plus private helpers for repository-view context and focus-deck resolution
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp`
|
||||
- `ClearActiveRun()` now captures retained repository-view context before clearing the active run
|
||||
- `StartTrainingRunFromDeck()` clears retained idle-context state when a new run begins
|
||||
- `RefreshRepositoryViews()` now derives coach memory, review-program summary, queue state, and coach briefs from retained repository-view context when no run is active
|
||||
- recommended/follow-up deck builders now resolve their source deck from repository context instead of requiring a live active deck
|
||||
|
||||
## Product effect
|
||||
|
||||
The post-review boundary is now more truthful:
|
||||
|
||||
- explicit run clear no longer erases open carryover pressure that still exists in repository state
|
||||
- coach guidance and queue materialization can remain visible after run clear when open review work still exists
|
||||
- the dashboard can stay aligned with repository-derived carryover without reviving stale active-review-plan state
|
||||
- launch-budget and queue-follow-up surfaces can still resolve a usable focus deck after run clear when repository context identifies one
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `ClearActiveRun()` preserves enough context for repository-derived coach state to survive the clear-run boundary
|
||||
- `RefreshRepositoryViews()` no longer hard-resets repository-derived coach/queue state solely because there is no active run
|
||||
- active review-plan inspection remains cleared when the run is gone
|
||||
- coach recommended/follow-up deck resolution still works after the clear-run transition when repository focus deck context exists
|
||||
- full product build succeeds
|
||||
|
||||
## Validation checklist
|
||||
|
||||
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
|
||||
2. confirm `ClearActiveRun()` captures retained repository-view context before zeroing the active run
|
||||
3. confirm `RefreshRepositoryViews()` can derive coach and queue state from retained repository-view context when idle
|
||||
4. confirm active review-plan state is still cleared after run clear
|
||||
5. confirm coach deck builders resolve focus deck state without requiring a live active run deck
|
||||
|
||||
That is the packet.
|
||||
Loading…
Add table
Reference in a new issue