#include "HyperTwistTraining/HyperTwistTrainingSubsystem.h"

#include "HyperTwistRecognition/HyperTwistVisionClient.h"
#include "HyperTwistRecognition/HyperTwistRecognitionReplayLibrary.h"
#include "HyperTwistReplay/HyperTwistReplayLibrary.h"
#include "HyperTwistReplay/HyperTwistReplayReviewLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingCoachLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingPersistenceLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h"
#include "JsonObjectConverter.h"

namespace HyperTwistTrainingSubsystemInternal
{
	const TCHAR* ActiveCoachSessionQueueId = TEXT("coach_queue_active");

	struct FResolvedCoachCaseBudget
	{
		int32 RequestedCaseCount = 0;
		int32 ResolvedCaseCount = 0;
		FString ReasonLine;
	};

	FResolvedCoachCaseBudget ResolvePreferredCoachCaseBudget(
		int32 MaxCases,
		EHyperTwistTrainingCoachGuidanceLane DeckLane,
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot,
		bool bQueuedLaunch
	);

	EHyperTwistCoachPriority CoachPriorityFromScore(const float Score)
	{
		if (Score >= 85.0f)
		{
			return EHyperTwistCoachPriority::Critical;
		}
		if (Score >= 65.0f)
		{
			return EHyperTwistCoachPriority::Elevated;
		}
		if (Score >= 40.0f)
		{
			return EHyperTwistCoachPriority::Advisory;
		}
		return EHyperTwistCoachPriority::Informational;
	}

	FString ResolveQueueActionLabel(const FString& SourceLabel)
	{
		if (SourceLabel == TEXT("follow-up-brief"))
		{
			return TEXT("Start coach follow-up run");
		}
		if (SourceLabel == TEXT("archive-policy"))
		{
			return TEXT("Start archive retention run");
		}
		if (SourceLabel == TEXT("primary-brief"))
		{
			return TEXT("Start coach recommended run");
		}
		return TEXT("Start queued coach run");
	}

	EHyperTwistTrainingCoachGuidanceLane GuidanceLaneFromQueueSourceLabel(const FString& SourceLabel)
	{
		if (SourceLabel == TEXT("primary-brief"))
		{
			return EHyperTwistTrainingCoachGuidanceLane::Recommended;
		}
		if (SourceLabel == TEXT("follow-up-brief"))
		{
			return EHyperTwistTrainingCoachGuidanceLane::FollowUp;
		}

		return EHyperTwistTrainingCoachGuidanceLane::None;
	}

	template <typename TEnum>
	FString EnumDisplayName(const TEnum Value)
	{
		if (const UEnum* Enum = StaticEnum<TEnum>())
		{
			return Enum->GetNameStringByValue(static_cast<int64>(Value));
		}

		return TEXT("Unknown");
	}

	template <typename TEnum>
	TEnum EnumValueFromName(const FString& Value, const TEnum Fallback)
	{
		if (Value.IsEmpty())
		{
			return Fallback;
		}
		if (const UEnum* Enum = StaticEnum<TEnum>())
		{
			const int64 RawValue = Enum->GetValueByNameString(Value);
			if (RawValue != INDEX_NONE)
			{
				return static_cast<TEnum>(RawValue);
			}
		}

		return Fallback;
	}

	EHyperTwistTrainingPenalty CombinePenalties(
		const EHyperTwistTrainingPenalty LeftPenalty,
		const EHyperTwistTrainingPenalty RightPenalty
	)
	{
		if (LeftPenalty == EHyperTwistTrainingPenalty::DNF || RightPenalty == EHyperTwistTrainingPenalty::DNF)
		{
			return EHyperTwistTrainingPenalty::DNF;
		}
		if (LeftPenalty == EHyperTwistTrainingPenalty::Plus2 || RightPenalty == EHyperTwistTrainingPenalty::Plus2)
		{
			return EHyperTwistTrainingPenalty::Plus2;
		}

		return EHyperTwistTrainingPenalty::None;
	}

	EHyperTwistTrainingPenalty ComputeInspectionPenalty(
		const int32 InspectionElapsedMs,
		const FHyperTwistTrainingTimingPolicy& TimingPolicy
	)
	{
		if (!TimingPolicy.bInspectionEnabled
			|| !TimingPolicy.bInspectionPenaltiesEnabled
			|| TimingPolicy.InspectionDurationMs <= 0
			|| InspectionElapsedMs <= TimingPolicy.InspectionDurationMs)
		{
			return EHyperTwistTrainingPenalty::None;
		}

		return InspectionElapsedMs <= TimingPolicy.InspectionDurationMs + 2000
			? EHyperTwistTrainingPenalty::Plus2
			: EHyperTwistTrainingPenalty::DNF;
	}

	int32 ResolveLiveTimerReplayTimeMs(const FHyperTwistTrainingLiveTimerState& LiveTimerState)
	{
		return FMath::Max(0, LiveTimerState.InspectionElapsedMs + LiveTimerState.SolveElapsedMs);
	}

	bool ShouldPreferRecognitionReplayReviewForActiveRun(
		const FHyperTwistTrainingRunState& RunState,
		const FHyperTwistTrainingCoachActionPlan& ActionPlan
	)
	{
		if (!RunState.IsStructurallyValid() || !ActionPlan.IsStructurallyValid())
		{
			return false;
		}

		if (!ActionPlan.SourceSessionId.IsEmpty()
			&& ActionPlan.SourceSessionId != RunState.Session.TrainingSessionId)
		{
			return false;
		}

		return ActionPlan.bPreferRecognitionReplayReview;
	}

	FHyperTwistTrainingReviewPolicy ResolveActiveReviewPolicy(
		const FHyperTwistTrainingRunState& RunState,
		const FHyperTwistTrainingCoachActionPlan& ActionPlan,
		EHyperTwistTrainingDeliveryMode DeliveryMode
	)
	{
		FHyperTwistTrainingReviewPolicy ReviewPolicy =
			UHyperTwistTrainingRepositoryLibrary::GetDefaultReviewPolicy(DeliveryMode);
		if (!ShouldPreferRecognitionReplayReviewForActiveRun(RunState, ActionPlan))
		{
			return ReviewPolicy;
		}

		ReviewPolicy.bPreferRecognitionReplayReview = true;
		if (!ReviewPolicy.PolicyLabel.Contains(TEXT("recognition-review"), ESearchCase::IgnoreCase))
		{
			ReviewPolicy.PolicyLabel = ReviewPolicy.PolicyLabel.IsEmpty()
				? TEXT("recognition-review")
				: FString::Printf(TEXT("%s-recognition-review"), *ReviewPolicy.PolicyLabel);
		}
		ReviewPolicy.MaxCases = ReviewPolicy.MaxCases > 0 ? FMath::Min(ReviewPolicy.MaxCases, 4) : 4;
		ReviewPolicy.NewCaseBias = FMath::Min(ReviewPolicy.NewCaseBias, -20.0f);
		ReviewPolicy.DueCaseBias = FMath::Max(ReviewPolicy.DueCaseBias, 105.0f);
		ReviewPolicy.RecognitionBias = FMath::Max(ReviewPolicy.RecognitionBias, 130.0f);
		ReviewPolicy.bPreferShortReviewSets = true;
		return ReviewPolicy;
	}

	FString ResolveQueueSuppressionLine(const FHyperTwistCoachSessionQueueSummary& QueueSummary)
	{
		const bool bHasPrimarySuppression =
			QueueSummary.bSuppressedPrimaryQueueCreation
			&& !QueueSummary.PrimaryQueueSuppressionReason.IsEmpty();
		const bool bHasFollowUpSuppression =
			QueueSummary.bSuppressedFollowUpQueueCreation
			&& !QueueSummary.FollowUpQueueSuppressionReason.IsEmpty();
		if (bHasPrimarySuppression && bHasFollowUpSuppression)
		{
			return FString::Printf(
				TEXT("Queue suppression: %s | %s"),
				*QueueSummary.PrimaryQueueSuppressionReason,
				*QueueSummary.FollowUpQueueSuppressionReason
			);
		}
		if (bHasPrimarySuppression)
		{
			return FString::Printf(
				TEXT("Queue suppression: %s"),
				*QueueSummary.PrimaryQueueSuppressionReason
			);
		}
		if (bHasFollowUpSuppression)
		{
			return FString::Printf(
				TEXT("Queue suppression: %s"),
				*QueueSummary.FollowUpQueueSuppressionReason
			);
		}

		return FString();
	}

	FHyperTwistTrainingTemplateLaunchProvenance BuildTemplateLaunchProvenance(
		const FHyperTwistTrainingSessionTemplate& SessionTemplate
	)
	{
		FHyperTwistTrainingTemplateLaunchProvenance Provenance;
		if (!SessionTemplate.IsStructurallyValid())
		{
			return Provenance;
		}

		Provenance.UserId = SessionTemplate.UserId;
		Provenance.TemplateId = SessionTemplate.TemplateId;
		Provenance.SourceTemplateId = SessionTemplate.SourceTemplateId;
		Provenance.Title = SessionTemplate.Title;
		Provenance.TemplateKind = SessionTemplate.TemplateKind;
		Provenance.FocusDeckId = SessionTemplate.FocusDeckId;
		Provenance.MethodSegmentId = SessionTemplate.MethodSegmentId;
		Provenance.SuggestedMode = SessionTemplate.SuggestedMode;
		Provenance.SuggestedSelectionPolicy = SessionTemplate.SuggestedSelectionPolicy;
		Provenance.RecommendedCaseCount = SessionTemplate.RecommendedCaseCount;
		Provenance.FocusCaseIds = SessionTemplate.FocusCaseIds;
		Provenance.GuidanceLabel = SessionTemplate.GuidanceLabel;
		Provenance.SourceReviewPlanId = SessionTemplate.SourceReviewPlanId;
		Provenance.bPreferReviewRun = SessionTemplate.bPreferReviewRun;
		Provenance.bCoachReview = SessionTemplate.bCoachReview;
		Provenance.bPreferShortReviewSet = SessionTemplate.bPreferShortReviewSet;
		return Provenance;
	}

	void PersistActiveRunTemplateLaunchProvenance(
		FHyperTwistTrainingRepositoryState& RepositoryState,
		FHyperTwistTrainingRunState& ActiveRunState,
		const FHyperTwistTrainingSessionTemplate& SessionTemplate
	)
	{
		if (!ActiveRunState.IsStructurallyValid())
		{
			return;
		}

		const FHyperTwistTrainingTemplateLaunchProvenance Provenance =
			BuildTemplateLaunchProvenance(SessionTemplate);
		if (!Provenance.IsStructurallyValid())
		{
			return;
		}

		ActiveRunState.TemplateLaunchProvenance = Provenance;
		RepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
			RepositoryState,
			ActiveRunState
		);
	}

	FString FormatLaunchBudgetLabel(const int32 CaseCount)
	{
		return FString::Printf(TEXT("Launch cases: %d"), CaseCount);
	}

	FResolvedCoachCaseBudget ResolveQueueLaunchBudgetFromEntry(
		const FHyperTwistTrainingCoachSessionQueueStateEntry& QueueEntry,
		const FHyperTwistTrainingDeck& QueueDeck,
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot,
		int32 MaxCases
	)
	{
		if (QueueEntry.FocusCaseIds.Num() == 0)
		{
			return ResolvePreferredCoachCaseBudget(
				MaxCases,
				GuidanceLaneFromQueueSourceLabel(QueueEntry.SourceLabel),
				CoachMemorySnapshot,
				true
			);
		}

		FResolvedCoachCaseBudget Result;
		Result.RequestedCaseCount = FMath::Max(1, QueueEntry.FocusCaseIds.Num());
		Result.ResolvedCaseCount = QueueDeck.Cases.Num() > 0
			? QueueDeck.Cases.Num()
			: (MaxCases > 0
				? FMath::Min(Result.RequestedCaseCount, MaxCases)
				: Result.RequestedCaseCount);
		if (QueueEntry.bHasTightenedLaunchOverflow && Result.RequestedCaseCount > Result.ResolvedCaseCount)
		{
			Result.ReasonLine = FString::Printf(
				TEXT("queued snapshot keeps the tightened launch scope active (%d deferred cases)"),
				FMath::Max(0, QueueEntry.DeferredLaunchCaseCount)
			);
		}
		else if (QueueEntry.bNeedsDeferredLaunchRecovery && Result.RequestedCaseCount > Result.ResolvedCaseCount)
		{
			Result.ReasonLine = FString::Printf(
				TEXT("queued snapshot preserves deferred follow-up recovery (%d deferred cases)"),
				FMath::Max(0, QueueEntry.DeferredLaunchCaseCount)
			);
		}

		return Result;
	}

	FString ResolveGeneratedModeSelectorChoiceLabel(
		const FHyperTwistTrainingDeck& Deck,
		const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice
	)
	{
		const FHyperTwistTrainingImportedRuntimeSelector* MatchingSelector =
			Deck.ImportedRuntimeSurface.Selectors.FindByPredicate(
				[&Choice](const FHyperTwistTrainingImportedRuntimeSelector& Candidate)
				{
					return Candidate.SelectorId == Choice.SelectorId;
				}
			);
		if (MatchingSelector != nullptr && !MatchingSelector->Label.IsEmpty())
		{
			return MatchingSelector->Label;
		}
		if (!Choice.SelectorBinding.IsEmpty())
		{
			return Choice.SelectorBinding;
		}
		return Choice.SelectorId;
	}

	FString FormatGeneratedModeSelectorSummary(
		const FHyperTwistTrainingDeck& Deck,
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
	)
	{
		if (!LaunchRequest.IsStructurallyValid())
		{
			return FString();
		}

		TArray<FString> SelectorParts;
		for (const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice : LaunchRequest.LaunchConfig.SelectorChoices)
		{
			if (!Choice.IsStructurallyValid())
			{
				continue;
			}

			const FString Label = ResolveGeneratedModeSelectorChoiceLabel(Deck, Choice);
			const FString Value = !Choice.DisplayValue.IsEmpty() ? Choice.DisplayValue : Choice.SelectedValue;
			SelectorParts.Add(FString::Printf(TEXT("%s=%s"), *Label, *Value));
		}

		return SelectorParts.Num() > 0 ? FString::Join(SelectorParts, TEXT(" | ")) : TEXT("no selector choices");
	}

	FString SanitizeGeneratedModeToken(const FString& Value)
	{
		FString Sanitized;
		Sanitized.Reserve(Value.Len());

		for (const TCHAR Character : Value)
		{
			if (FChar::IsAlnum(Character))
			{
				Sanitized.AppendChar(FChar::ToLower(Character));
			}
			else if (Sanitized.IsEmpty() || Sanitized[Sanitized.Len() - 1] != TEXT('-'))
			{
				Sanitized.AppendChar(TEXT('-'));
			}
		}

		while (Sanitized.StartsWith(TEXT("-")))
		{
			Sanitized.RightChopInline(1, EAllowShrinking::No);
		}
		while (Sanitized.EndsWith(TEXT("-")))
		{
			Sanitized.LeftChopInline(1, EAllowShrinking::No);
		}

		return Sanitized.IsEmpty() ? TEXT("value") : Sanitized;
	}

	const FHyperTwistTrainingCase* FindFirstStructurallyValidCase(const FHyperTwistTrainingDeck& Deck)
	{
		return Deck.Cases.FindByPredicate(
			[](const FHyperTwistTrainingCase& Candidate)
			{
				return Candidate.IsStructurallyValid();
			}
		);
	}

	EHyperTwistTrainingPromptKind ResolveGeneratedModePromptKind(
		const FHyperTwistTrainingCase& SeedCase,
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
	)
	{
		const FString RuntimeModeId = LaunchRequest.LaunchConfig.RuntimeModeId.ToLower();
		const FString GeneratorType = LaunchRequest.LaunchConfig.GeneratorType.ToLower();
		if (RuntimeModeId.Contains(TEXT("recognition")) || GeneratorType.Contains(TEXT("recognition")))
		{
			return EHyperTwistTrainingPromptKind::Recognition;
		}
		if (RuntimeModeId.Contains(TEXT("state"))
			|| GeneratorType.Contains(TEXT("state"))
			|| RuntimeModeId.Contains(TEXT("scramble"))
			|| GeneratorType.Contains(TEXT("scramble")))
		{
			return EHyperTwistTrainingPromptKind::State;
		}
		if ((SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Algorithm
				|| SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Sequence
				|| SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Memo)
			&& SeedCase.CanonicalNotation.IsEmpty())
		{
			return EHyperTwistTrainingPromptKind::State;
		}

		return SeedCase.PromptKind;
	}

	FString BuildGeneratedModeExecutionSessionId(
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
	)
	{
		const FString BaseSessionId = !LaunchRequest.LaunchConfig.TrainingSessionId.IsEmpty()
			? LaunchRequest.LaunchConfig.TrainingSessionId
			: TEXT("generated-mode");
		const FString ExecutionToken = FGuid::NewGuid().ToString(EGuidFormats::Digits).ToLower();
		return FString::Printf(
			TEXT("%s__generated__%s__%s"),
			*BaseSessionId,
			*SanitizeGeneratedModeToken(LaunchRequest.RequestId),
			*ExecutionToken
		);
	}

	FString BuildGeneratedModeCanonicalStateRef(
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
	)
	{
		const FString SurfaceToken = SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.SurfaceId);
		const FString RuntimeToken = SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.RuntimeModeId);
		const FString RequestToken = SanitizeGeneratedModeToken(LaunchRequest.RequestId);
		return FString::Printf(
			TEXT("generated-mode/%s/%s/%s"),
			*SurfaceToken,
			*RuntimeToken,
			*RequestToken
		);
	}

	bool DoGeneratedModeSelectorChoiceSetsMatch(
		const TArray<FHyperTwistTrainingImportedRuntimeSelector>& Selectors,
		const TArray<FHyperTwistTrainingImportedRuntimeSelectorChoice>& LeftChoices,
		const TArray<FHyperTwistTrainingImportedRuntimeSelectorChoice>& RightChoices
	)
	{
		for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : Selectors)
		{
			const FHyperTwistTrainingImportedRuntimeSelectorChoice* LeftChoice =
				LeftChoices.FindByPredicate(
					[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
					{
						return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
					}
				);
			const FHyperTwistTrainingImportedRuntimeSelectorChoice* RightChoice =
				RightChoices.FindByPredicate(
					[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
					{
						return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
					}
				);
			if (LeftChoice == nullptr || RightChoice == nullptr)
			{
				return false;
			}
			if (LeftChoice->SelectedValue != RightChoice->SelectedValue)
			{
				return false;
			}
		}

		return true;
	}

	bool DoesGeneratedModeLaunchRequestMatchLaunchConfig(
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest,
		const FHyperTwistTrainingImportedRuntimeSurface& RuntimeSurface,
		const FHyperTwistTrainingImportedGeneratedModeLaunchConfig& ExpectedLaunchConfig
	)
	{
		return LaunchRequest.IsStructurallyValid()
			&& LaunchRequest.LaunchConfig.DeckId == ExpectedLaunchConfig.DeckId
			&& LaunchRequest.LaunchConfig.SurfaceId == ExpectedLaunchConfig.SurfaceId
			&& LaunchRequest.LaunchConfig.RuntimeModeId.Equals(
				ExpectedLaunchConfig.RuntimeModeId,
				ESearchCase::IgnoreCase
			)
			&& DoGeneratedModeSelectorChoiceSetsMatch(
				RuntimeSurface.Selectors,
				LaunchRequest.LaunchConfig.SelectorChoices,
				ExpectedLaunchConfig.SelectorChoices
			);
	}

	bool TryResolveGeneratedModeExecutionLaunchConfig(
		const FHyperTwistTrainingRunState& RunState,
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& ExistingLaunchRequest,
		FHyperTwistTrainingImportedGeneratedModeLaunchConfig& OutLaunchConfig,
		bool& bOutRequiresLaunchRequestRefresh,
		FString& OutBlockedReason
	)
	{
		OutLaunchConfig = FHyperTwistTrainingImportedGeneratedModeLaunchConfig();
		bOutRequiresLaunchRequestRefresh = false;
		OutBlockedReason.Reset();

		if (!RunState.IsStructurallyValid())
		{
			OutBlockedReason = TEXT("Generated-mode execution requires an active training run.");
			return false;
		}

		FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
		if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
				RunState.ActiveDeck,
				RuntimeSurface)
			|| !RuntimeSurface.IsStructurallyValid()
			|| !RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
		{
			OutBlockedReason = TEXT("Active run is not a generated-mode imported runtime surface.");
			return false;
		}

		if (!RunState.ImportedRuntimeSelectionState.IsStructurallyValid()
			|| RunState.ImportedRuntimeSelectionState.SurfaceId != RuntimeSurface.SurfaceId
			|| !RunState.ImportedRuntimeSelectionState.SurfaceKind.Equals(
				RuntimeSurface.SurfaceKind,
				ESearchCase::IgnoreCase))
		{
			OutBlockedReason =
				TEXT("Generated-mode execution requires imported selector state that matches the active runtime surface.");
			return false;
		}

		for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
		{
			const FHyperTwistTrainingImportedRuntimeSelectorChoice* ActiveChoice =
				RunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
					[&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
					{
						return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
					}
				);
			if (ActiveChoice == nullptr)
			{
				OutBlockedReason = FString::Printf(
					TEXT("Generated-mode execution is blocked because selector %s is unresolved."),
					*Selector.Label
				);
				return false;
			}
		}

		if (!UHyperTwistTrainingCatalogLibrary::TryBuildImportedGeneratedModeLaunchConfig(
				RunState.ActiveDeck,
				RunState.ImportedRuntimeSelectionState,
				RunState.Session,
				OutLaunchConfig))
		{
			OutBlockedReason =
				TEXT("Generated-mode execution could not derive a structurally valid launch request from the active selector state.");
			return false;
		}

		bOutRequiresLaunchRequestRefresh = !DoesGeneratedModeLaunchRequestMatchLaunchConfig(
			ExistingLaunchRequest,
			RuntimeSurface,
			OutLaunchConfig
		);
		return true;
	}

	bool TryBuildGeneratedModeExecutionDeck(
		const FHyperTwistTrainingDeck& SourceDeck,
		const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest,
		FHyperTwistTrainingDeck& OutDeck,
		FString& OutBlockedReason
	)
	{
		OutDeck = FHyperTwistTrainingDeck();
		OutBlockedReason.Reset();

		if (!SourceDeck.IsStructurallyValid())
		{
			OutBlockedReason = TEXT("Generated-mode executor requires a structurally valid source deck.");
			return false;
		}
		if (!LaunchRequest.IsStructurallyValid())
		{
			OutBlockedReason = TEXT("Generated-mode executor requires a structurally valid launch request.");
			return false;
		}

		const FHyperTwistTrainingCase* SeedCase = FindFirstStructurallyValidCase(SourceDeck);
		if (SeedCase == nullptr)
		{
			OutBlockedReason = TEXT("Generated-mode executor could not find a structurally valid source case.");
			return false;
		}

		const FString SelectorSummary = FormatGeneratedModeSelectorSummary(SourceDeck, LaunchRequest);
		const FString PromptBaseLabel = !LaunchRequest.LaunchConfig.SurfaceLabel.IsEmpty()
			? LaunchRequest.LaunchConfig.SurfaceLabel
			: SourceDeck.Title;
		const FString CaseExecutionNote = FString::Printf(
			TEXT("Owned generated-mode execution case produced from request %s."),
			*LaunchRequest.RequestId
		);
		const FString DeckExecutionNote = FString::Printf(
			TEXT("Owned generated-mode execution deck produced from request %s."),
			*LaunchRequest.RequestId
		);

		FHyperTwistTrainingCase GeneratedCase = *SeedCase;
		GeneratedCase.CaseId = FString::Printf(
			TEXT("%s/generated/%s"),
			*SourceDeck.DeckId,
			*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
		);
		GeneratedCase.PuzzleId = !LaunchRequest.LaunchConfig.PuzzleId.IsEmpty()
			? LaunchRequest.LaunchConfig.PuzzleId
			: SeedCase->PuzzleId;
		GeneratedCase.PromptKind = ResolveGeneratedModePromptKind(*SeedCase, LaunchRequest);
		GeneratedCase.PromptLabel = !PromptBaseLabel.IsEmpty() && !SelectorSummary.IsEmpty()
			? FString::Printf(
				TEXT("%s | %s"),
				*PromptBaseLabel,
				*SelectorSummary
			)
			: PromptBaseLabel;
		GeneratedCase.CanonicalStateRef = BuildGeneratedModeCanonicalStateRef(LaunchRequest);
		GeneratedCase.CanonicalNotation.Reset();
		GeneratedCase.AlternateNotations.Reset();
		GeneratedCase.ScrambleNotation.Reset();
		GeneratedCase.SubsetId = SourceDeck.SubsetId;
		GeneratedCase.Difficulty = SeedCase->Difficulty;
		GeneratedCase.Tags = SeedCase->Tags;
		GeneratedCase.Tags.AddUnique(TEXT("runtime-surface:generated-mode"));
		GeneratedCase.Tags.AddUnique(TEXT("generated-mode:owned-execution"));
		GeneratedCase.Tags.AddUnique(
			FString::Printf(
				TEXT("generated-request:%s"),
				*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
			)
		);
		GeneratedCase.Tags.AddUnique(
			FString::Printf(
				TEXT("generated-surface:%s"),
				*SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.SurfaceId)
			)
		);
		for (const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice : LaunchRequest.LaunchConfig.SelectorChoices)
		{
			if (!Choice.IsStructurallyValid())
			{
				continue;
			}

			GeneratedCase.Tags.AddUnique(
				FString::Printf(
					TEXT("generated-selector:%s=%s"),
					*SanitizeGeneratedModeToken(Choice.SelectorId),
					*SanitizeGeneratedModeToken(Choice.SelectedValue)
				)
			);
		}
		GeneratedCase.AllowedDeliveryModes = SeedCase->AllowedDeliveryModes;
		if (GeneratedCase.AllowedDeliveryModes.Num() == 0)
		{
			GeneratedCase.AllowedDeliveryModes = SourceDeck.DeliveryModes;
		}
		GeneratedCase.AllowedDeliveryModes.AddUnique(LaunchRequest.LaunchConfig.DeliveryMode);
		GeneratedCase.TimeTargetMs = SeedCase->TimeTargetMs;
		GeneratedCase.SourceAttribution = SeedCase->SourceAttribution.IsStructurallyValid()
			? SeedCase->SourceAttribution
			: SourceDeck.SourceAttribution;
		if (GeneratedCase.SourceAttribution.SourceCaseId.IsEmpty())
		{
			GeneratedCase.SourceAttribution.SourceCaseId = SeedCase->CaseId;
		}
		GeneratedCase.SourceAttribution.SourceNotes = GeneratedCase.SourceAttribution.SourceNotes.IsEmpty()
			? CaseExecutionNote
			: FString::Printf(
				TEXT("%s | %s"),
				*GeneratedCase.SourceAttribution.SourceNotes,
				*CaseExecutionNote
			);

		OutDeck = SourceDeck;
		OutDeck.SelectionPolicy = EHyperTwistTrainingSelectionPolicy::Scripted;
		OutDeck.Title = !SourceDeck.Title.IsEmpty()
			? SourceDeck.Title
			: (!LaunchRequest.LaunchConfig.SurfaceLabel.IsEmpty()
				? LaunchRequest.LaunchConfig.SurfaceLabel
				: TEXT("Generated mode deck"));
		OutDeck.bSupportsAlgorithmReveal =
			SourceDeck.bSupportsAlgorithmReveal && !GeneratedCase.CanonicalNotation.IsEmpty();
		OutDeck.Cases.Reset();
		OutDeck.Cases.Add(GeneratedCase);
		OutDeck.Tags.AddUnique(TEXT("runtime-surface:generated-mode"));
		OutDeck.Tags.AddUnique(TEXT("generated-mode:owned-execution"));
		OutDeck.Tags.AddUnique(
			FString::Printf(
				TEXT("generated-request:%s"),
				*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
			)
		);
		OutDeck.ImportedRuntimeSurface = SourceDeck.ImportedRuntimeSurface;
		OutDeck.SourceAttribution.SourceNotes = OutDeck.SourceAttribution.SourceNotes.IsEmpty()
			? DeckExecutionNote
			: FString::Printf(
				TEXT("%s | %s"),
				*OutDeck.SourceAttribution.SourceNotes,
				*DeckExecutionNote
			);

		if (!OutDeck.IsStructurallyValid() || !OutDeck.ImportedRuntimeSurface.IsStructurallyValid())
		{
			OutBlockedReason = TEXT("Generated-mode executor could not build a structurally valid owned execution deck.");
			return false;
		}

		return true;
	}

	TArray<FString> ExtractCaseIdsFromDeck(const FHyperTwistTrainingDeck& Deck)
	{
		TArray<FString> CaseIds;
		for (const FHyperTwistTrainingCase& TrainingCase : Deck.Cases)
		{
			if (!TrainingCase.CaseId.IsEmpty())
			{
				CaseIds.Add(TrainingCase.CaseId);
			}
		}

		return CaseIds;
	}

	FResolvedCoachCaseBudget ResolvePreferredCoachCaseBudget(
		const int32 MaxCases,
		const EHyperTwistTrainingCoachGuidanceLane DeckLane,
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot,
		const bool bQueuedLaunch)
	{
		FResolvedCoachCaseBudget Result;
		Result.RequestedCaseCount = MaxCases > 0 ? MaxCases : 3;
		Result.ResolvedCaseCount = Result.RequestedCaseCount;
		TArray<FString> BudgetReasons;
		if (CoachMemorySnapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
			&& DeckLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp)
		{
			Result.ResolvedCaseCount = FMath::Max(1, Result.ResolvedCaseCount - 1);
			BudgetReasons.Add(TEXT("follow-up guidance is tightening the launch slice"));
		}
		else if (CoachMemorySnapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::Recommended
			&& DeckLane == EHyperTwistTrainingCoachGuidanceLane::Recommended
			&& Result.ResolvedCaseCount <= 3
			&& (CoachMemorySnapshot.bHasRepeatRecommendationPressure
				|| CoachMemorySnapshot.RecommendedGuidanceContinueBias > 0
				|| CoachMemorySnapshot.RecurringCoachCaseIds.Num() >= 3))
		{
			Result.ResolvedCaseCount += 1;
			BudgetReasons.Add(TEXT("recommendation pressure is widening the launch slice"));
		}

		if (CoachMemorySnapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::Queue
			&& bQueuedLaunch
			&& DeckLane != EHyperTwistTrainingCoachGuidanceLane::FollowUp
			&& (CoachMemorySnapshot.ScheduleDeferredEventCount > 0
				|| CoachMemorySnapshot.ScheduleManualRescheduleEventCount > 0
				|| CoachMemorySnapshot.bHasQueueExecutionCompletionGap))
		{
			Result.ResolvedCaseCount += 1;
			BudgetReasons.Add(TEXT("queue-first handoff is broadening queued recovery work"));
		}
		else if (CoachMemorySnapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::FollowUp
			&& DeckLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
			&& (CoachMemorySnapshot.FollowUpReadyCoachSequenceCount > 0
				|| CoachMemorySnapshot.ScheduleBlockedFollowUpEventCount > 0
				|| CoachMemorySnapshot.FollowUpGuidanceContinueBias > 0))
		{
			Result.ResolvedCaseCount = FMath::Max(1, Result.ResolvedCaseCount - 1);
			BudgetReasons.Add(TEXT("follow-up-first handoff is keeping the launch tighter"));
		}
		else if (CoachMemorySnapshot.PreferredCoachHandoffKind == EHyperTwistTrainingCoachHandoffKind::Recommended
			&& DeckLane == EHyperTwistTrainingCoachGuidanceLane::Recommended
			&& Result.ResolvedCaseCount <= 4
			&& (CoachMemorySnapshot.bHasRepeatRecommendationPressure
				|| CoachMemorySnapshot.RecommendedGuidanceContinueBias > 0
				|| CoachMemorySnapshot.RecurringCoachCaseIds.Num() >= 2))
		{
			Result.ResolvedCaseCount += 1;
			BudgetReasons.Add(TEXT("recommended-first handoff is widening recommendation work"));
		}

		const bool bMatchesPreferredGuidanceLane =
			DeckLane != EHyperTwistTrainingCoachGuidanceLane::None
			&& DeckLane == CoachMemorySnapshot.PreferredGuidanceLane;
		if (CoachMemorySnapshot.PreferredLaunchBudgetBias > 0
			&& Result.ResolvedCaseCount <= 4
			&& (bMatchesPreferredGuidanceLane || bQueuedLaunch))
		{
			Result.ResolvedCaseCount += 1;
			BudgetReasons.Add(TEXT("successful broadened-launch history is widening the next launch"));
		}
		else if (CoachMemorySnapshot.PreferredLaunchBudgetBias < 0
			&& Result.ResolvedCaseCount > 1
			&& (bMatchesPreferredGuidanceLane
				|| DeckLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
				|| bQueuedLaunch))
		{
			Result.ResolvedCaseCount = FMath::Max(1, Result.ResolvedCaseCount - 1);
			if (CoachMemorySnapshot.PreferredLaunchBudgetSourceLabel
				== TEXT("recommendation-history-deferred-tightened-launch"))
			{
				BudgetReasons.Add(
					DeckLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
						? TEXT("successful deferred tightened-launch history is keeping the continuation slice narrow enough to recover deferred coach work")
						: (bQueuedLaunch
							? TEXT("successful deferred tightened-launch history is keeping queued continuation work narrow enough to recover deferred coach work")
							: TEXT("successful deferred tightened-launch history is narrowing the next launch to continue deferred coach work"))
				);
			}
			else if (CoachMemorySnapshot.PreferredLaunchBudgetSourceLabel.StartsWith(TEXT("coach-memory-schedule-")))
			{
				BudgetReasons.Add(
					CoachMemorySnapshot.bHasBlockedFollowUpScheduleFriction
						? (DeckLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
							? TEXT("blocked follow-up schedule friction is keeping the continuation slice narrow enough to unblock follow-up queue work")
							: (bQueuedLaunch
								? TEXT("blocked follow-up schedule friction is keeping queued continuation work narrow enough to reduce deferred queue pressure")
								: TEXT("blocked follow-up schedule friction is narrowing the next launch before broader guidance resumes")))
						: (DeckLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
							? TEXT("schedule-friction recovery is keeping the continuation slice narrow enough to stabilize follow-up queue work")
							: (bQueuedLaunch
								? TEXT("schedule-friction recovery is keeping queued continuation work narrow enough to reduce deferred queue pressure")
								: TEXT("schedule-friction recovery is narrowing the next launch before broader guidance resumes")))
				);
			}
			else
			{
				BudgetReasons.Add(TEXT("successful tightened-launch history is narrowing the next launch"));
			}
		}

		Result.ResolvedCaseCount = FMath::Max(1, Result.ResolvedCaseCount);
		Result.ReasonLine = BudgetReasons.Num() > 0
			? FString::Join(BudgetReasons, TEXT("; "))
			: FString();
		return Result;
	}

	bool IsStrongMethodDrillFollowUpMemory(
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
	{
		if (CoachMemorySnapshot.PreferredGuidanceSourceLabel
				== 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(
				TEXT("coach-memory-dashboard-method-drill-follow-up-packet-strong-")))
		{
			return true;
		}

		return CoachMemorySnapshot.MethodDrillFollowUpHistoryCount >= 2
			&& CoachMemorySnapshot.StrongMethodDrillFollowUpHistoryCount
				>= CoachMemorySnapshot.WeakMethodDrillFollowUpHistoryCount
			&& CoachMemorySnapshot.MethodDrillFollowUpAverageOutcomeScore >= 60.0f;
	}

	bool IsWeakMethodDrillFollowUpMemory(
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
	{
		if (CoachMemorySnapshot.PreferredGuidanceSourceLabel
				== 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(
				TEXT("coach-memory-dashboard-method-drill-follow-up-packet-weak-")))
		{
			return true;
		}

		return CoachMemorySnapshot.MethodDrillFollowUpHistoryCount >= 2
			&& CoachMemorySnapshot.WeakMethodDrillFollowUpHistoryCount
				> CoachMemorySnapshot.StrongMethodDrillFollowUpHistoryCount
			&& CoachMemorySnapshot.MethodDrillFollowUpAverageOutcomeScore <= 55.0f;
	}

	bool IsStrongMethodDrillFollowUpPacketMemory(
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
	{
		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-"));
	}

	bool IsWeakMethodDrillFollowUpPacketMemory(
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
	{
		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-"));
	}

	EHyperTwistTrainingCoachHandoffKind MethodDrillFollowUpPacketHandoffKindFromSourceLabel(
		const FString& SourceLabel,
		const EHyperTwistTrainingCoachHandoffKind FallbackKind)
	{
		if (SourceLabel.EndsWith(TEXT("-queued")))
		{
			return EHyperTwistTrainingCoachHandoffKind::Queue;
		}
		if (SourceLabel.EndsWith(TEXT("-follow-up")))
		{
			return EHyperTwistTrainingCoachHandoffKind::FollowUp;
		}
		if (SourceLabel.EndsWith(TEXT("-recommended")))
		{
			return EHyperTwistTrainingCoachHandoffKind::Recommended;
		}

		return FallbackKind;
	}

	FString DescribeMethodDrillFollowUpPacketLane(
		const EHyperTwistTrainingCoachHandoffKind HandoffKind)
	{
		switch (HandoffKind)
		{
		case EHyperTwistTrainingCoachHandoffKind::Queue:
			return TEXT("queue-entry");
		case EHyperTwistTrainingCoachHandoffKind::FollowUp:
			return TEXT("follow-up-packet");
		case EHyperTwistTrainingCoachHandoffKind::Recommended:
			return TEXT("recommended-brief");
		default:
			return TEXT("follow-up-packet");
		}
	}

	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();
	}

	FString ResolveAlignedCoachFollowUpPacketStructureToken(
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
	{
		const bool bAlignedTightFollowUpPacketSource =
			CoachMemorySnapshot.PreferredGuidanceSourceLabel
				== TEXT("recommendation-history-aligned-tight-follow-up-outcome")
			|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
				== TEXT("recommendation-history-aligned-tight-follow-up-outcome")
			|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
				== TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up")
			|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
				== TEXT("coach-memory-aligned-follow-up-packet-structure-tight-follow-up");
		const bool bAlignedBroadRecommendedPacketSource =
			CoachMemorySnapshot.PreferredGuidanceSourceLabel
				== TEXT("recommendation-history-aligned-broad-recommended-outcome")
			|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
				== TEXT("recommendation-history-aligned-broad-recommended-outcome")
			|| CoachMemorySnapshot.PreferredGuidanceSourceLabel
				== TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended")
			|| CoachMemorySnapshot.PreferredCoachHandoffSourceLabel
				== TEXT("coach-memory-aligned-follow-up-packet-structure-broad-recommended");
		if (bAlignedTightFollowUpPacketSource && !bAlignedBroadRecommendedPacketSource)
		{
			return TEXT("aligned_packet_tight_follow_up_first");
		}
		if (bAlignedBroadRecommendedPacketSource && !bAlignedTightFollowUpPacketSource)
		{
			return TEXT("aligned_packet_broad_recommended_first");
		}

		return FString();
	}

	FHyperTwistTrainingSessionTemplate ApplyMethodDrillFollowUpMemoryBias(
		const FHyperTwistTrainingSessionTemplate& SessionTemplate,
		const FHyperTwistTrainingMethodDrillDiagnosticPacket& DiagnosticPacket,
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot)
	{
		if (!SessionTemplate.IsStructurallyValid())
		{
			return SessionTemplate;
		}

		const bool bStrongMethodDrillMemory = IsStrongMethodDrillFollowUpMemory(
			CoachMemorySnapshot
		);
		const bool bWeakMethodDrillMemory = IsWeakMethodDrillFollowUpMemory(CoachMemorySnapshot);
		const bool bStrongMethodDrillPacketMemory = IsStrongMethodDrillFollowUpPacketMemory(
			CoachMemorySnapshot
		);
		const bool bWeakMethodDrillPacketMemory = IsWeakMethodDrillFollowUpPacketMemory(
			CoachMemorySnapshot
		);
		if (bStrongMethodDrillMemory == bWeakMethodDrillMemory
			&& bStrongMethodDrillPacketMemory == bWeakMethodDrillPacketMemory)
		{
			return SessionTemplate;
		}

		FHyperTwistTrainingSessionTemplate Result = SessionTemplate;
		const int32 FocusCaseCount = Result.FocusCaseIds.Num();
		if (FocusCaseCount <= 0)
		{
			return Result;
		}

		if (bStrongMethodDrillMemory)
		{
			const EHyperTwistTrainingCoachHandoffKind PacketHandoffKind =
				MethodDrillFollowUpPacketHandoffKindFromSourceLabel(
					CoachMemorySnapshot.PreferredCoachHandoffSourceLabel,
					CoachMemorySnapshot.PreferredCoachHandoffKind);
			const FString PacketLaneLabel = DescribeMethodDrillFollowUpPacketLane(PacketHandoffKind);
			const bool bPacketSpecificNarrowing =
				bStrongMethodDrillPacketMemory && !bWeakMethodDrillPacketMemory;
			const int32 TightenedCaseCount = bPacketSpecificNarrowing
				? (PacketHandoffKind == EHyperTwistTrainingCoachHandoffKind::Recommended
					? (DiagnosticPacket.bBoundaryTriggeredByPendingCases ? 3 : 4)
					: (DiagnosticPacket.bBoundaryTriggeredByPendingCases ? 2 : 3))
				: (DiagnosticPacket.bBoundaryTriggeredByPendingCases ? 2 : 3);
			Result.RecommendedCaseCount = FMath::Clamp(
				FMath::Min(Result.RecommendedCaseCount, TightenedCaseCount),
				1,
				FocusCaseCount
			);
			if (Result.FocusCaseIds.Num() > Result.RecommendedCaseCount)
			{
				Result.FocusCaseIds.SetNum(Result.RecommendedCaseCount, EAllowShrinking::No);
			}
			Result.SuggestedSelectionPolicy = EHyperTwistTrainingSelectionPolicy::Scripted;
			Result.bPreferReviewRun = true;
			Result.bPreferShortReviewSet = true;
			if (Result.GuidanceLabel.IsEmpty())
			{
				Result.GuidanceLabel = bPacketSpecificNarrowing
					? FString::Printf(
						TEXT("successful drill-follow-up-packet history is keeping this %s packet narrow"),
						*PacketLaneLabel)
					: TEXT("successful drill follow-up history is keeping this packet narrow");
			}
			else
			{
				Result.GuidanceLabel = bPacketSpecificNarrowing
					? FString::Printf(
						TEXT("%s | successful drill-follow-up-packet history is keeping this %s packet narrow"),
						*Result.GuidanceLabel,
						*PacketLaneLabel)
					: FString::Printf(
						TEXT("%s | successful drill follow-up history is keeping this packet narrow"),
						*Result.GuidanceLabel);
			}
		}
		else
		{
			const EHyperTwistTrainingCoachHandoffKind PacketHandoffKind =
				MethodDrillFollowUpPacketHandoffKindFromSourceLabel(
					CoachMemorySnapshot.PreferredCoachHandoffSourceLabel,
					CoachMemorySnapshot.PreferredCoachHandoffKind);
			const FString PacketLaneLabel = DescribeMethodDrillFollowUpPacketLane(PacketHandoffKind);
			const bool bPacketSpecificRedirect =
				bWeakMethodDrillPacketMemory && !bStrongMethodDrillPacketMemory;
			const int32 BroadenDelta = bPacketSpecificRedirect
				? (PacketHandoffKind == EHyperTwistTrainingCoachHandoffKind::Recommended ? 3 : 2)
				: (DiagnosticPacket.bBoundaryTriggeredByPendingCases ? 1 : 2);
			Result.RecommendedCaseCount = FMath::Clamp(
				FMath::Max(
					Result.RecommendedCaseCount,
					FMath::Min(FocusCaseCount, Result.RecommendedCaseCount + BroadenDelta)
				),
				1,
				FocusCaseCount
			);
			if (!DiagnosticPacket.bBoundaryTriggeredByPendingCases)
			{
				Result.SuggestedSelectionPolicy = EHyperTwistTrainingSelectionPolicy::Weighted;
			}
			Result.bPreferShortReviewSet = Result.RecommendedCaseCount <= 4;
			if (Result.GuidanceLabel.IsEmpty())
			{
				Result.GuidanceLabel = bPacketSpecificRedirect
					? FString::Printf(
						TEXT("weak drill-follow-up-packet history is broadening this %s packet before redirect"),
						*PacketLaneLabel)
					: TEXT("weak drill follow-up history is broadening this packet before redirect");
			}
			else
			{
				Result.GuidanceLabel = bPacketSpecificRedirect
					? FString::Printf(
						TEXT("%s | weak drill-follow-up-packet history is broadening this %s packet before redirect"),
						*Result.GuidanceLabel,
						*PacketLaneLabel)
					: FString::Printf(
						TEXT("%s | weak drill follow-up history is broadening this packet before redirect"),
						*Result.GuidanceLabel);
			}
		}

		return Result.IsStructurallyValid() ? Result : SessionTemplate;
	}

	const FHyperTwistTrainingCoachSessionQueueStateEntry* FindNextRunnableCoachQueueEntry(
		const FHyperTwistTrainingCoachSessionQueueState& QueueState
	)
	{
		if (!QueueState.IsStructurallyValid())
		{
			return nullptr;
		}

		const FHyperTwistTrainingCoachSessionQueueStateEntry* BestEntry = nullptr;
		for (const FHyperTwistTrainingCoachSessionQueueStateEntry& Candidate : QueueState.Entries)
		{
			const bool bIsRunnable = Candidate.EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Ready
				|| (Candidate.EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Pending
					&& Candidate.bCanStartImmediately);
			if (!bIsRunnable)
			{
				continue;
			}

			if (BestEntry == nullptr || Candidate.SlotIndex < BestEntry->SlotIndex)
			{
				BestEntry = &Candidate;
			}
		}

		return BestEntry;
	}

	const FHyperTwistTrainingCoachSessionQueueStateEntry* FindCoachQueueEntryById(
		const FHyperTwistTrainingCoachSessionQueueState& QueueState,
		const FString& EntryId
	)
	{
		if (!QueueState.IsStructurallyValid() || EntryId.IsEmpty())
		{
			return nullptr;
		}

		return QueueState.Entries.FindByPredicate(
			[&EntryId](const FHyperTwistTrainingCoachSessionQueueStateEntry& Candidate)
			{
				return Candidate.EntryId == EntryId;
			}
		);
	}

	bool IsStartableCoachQueueEntryState(const EHyperTwistTrainingCoachSessionQueueEntryState EntryState)
	{
		return EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Pending
			|| EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Ready
			|| EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::InProgress;
	}

	const FHyperTwistTrainingCoachSessionQueueStateEntry* FindCarryoverResumeQueueEntry(
		const FHyperTwistTrainingCoachSessionQueueState& QueueState,
		const FHyperTwistTrainingReviewPlanState& ReviewPlan,
		const FHyperTwistTrainingCoachActionPlan& CarryForwardActionPlan,
		const FHyperTwistTrainingDeck& ReviewDeck
	)
	{
		if (!QueueState.IsStructurallyValid())
		{
			return nullptr;
		}

		const FString RootPlanId = !CarryForwardActionPlan.RootPlanId.IsEmpty()
			? CarryForwardActionPlan.RootPlanId
			: CarryForwardActionPlan.PlanId;
		const TArray<FString> ReviewCaseIds = ExtractCaseIdsFromDeck(ReviewDeck);
		const auto CountOverlap = [&ReviewCaseIds](const TArray<FString>& CandidateCaseIds) -> int32
		{
			int32 MatchCount = 0;
			for (const FString& ReviewCaseId : ReviewCaseIds)
			{
				if (!ReviewCaseId.IsEmpty() && CandidateCaseIds.Contains(ReviewCaseId))
				{
					MatchCount += 1;
				}
			}

			return MatchCount;
		};

		const FHyperTwistTrainingCoachSessionQueueStateEntry* BestEntry = nullptr;
		int32 BestScore = 0;
		for (const FHyperTwistTrainingCoachSessionQueueStateEntry& Entry : QueueState.Entries)
		{
			if (!Entry.IsStructurallyValid() || !IsStartableCoachQueueEntryState(Entry.EntryState))
			{
				continue;
			}

			int32 Score = 0;
			if (!ReviewPlan.PlanId.IsEmpty() && Entry.SourceReviewPlanId == ReviewPlan.PlanId)
			{
				Score += 500;
			}
			if (!CarryForwardActionPlan.PlanId.IsEmpty()
				&& Entry.CarryForwardPlanId == CarryForwardActionPlan.PlanId)
			{
				Score += 350;
			}
			if (!RootPlanId.IsEmpty() && Entry.RootPlanId == RootPlanId)
			{
				Score += 200;
			}
			if (!CarryForwardActionPlan.SourceSessionId.IsEmpty()
				&& Entry.SourceBriefTrainingSessionId == CarryForwardActionPlan.SourceSessionId)
			{
				Score += 125;
			}
			if (!ReviewPlan.SourceDeckId.IsEmpty() && Entry.FocusDeckId == ReviewPlan.SourceDeckId)
			{
				Score += 75;
			}

			const int32 OverlapCount = CountOverlap(Entry.FocusCaseIds);
			if (OverlapCount > 0)
			{
				Score += OverlapCount * 20;
				if (OverlapCount == ReviewCaseIds.Num())
				{
					Score += 40;
				}
			}
			if (!QueueState.ActiveEntryId.IsEmpty() && Entry.EntryId == QueueState.ActiveEntryId)
			{
				Score += 10;
			}

			if (Score > BestScore)
			{
				BestScore = Score;
				BestEntry = &Entry;
			}
		}

		return BestEntry;
	}

	FHyperTwistTrainingDeck BuildCoachQueueDeckFromEntry(
		const FHyperTwistTrainingCoachSessionQueueStateEntry& QueueEntry,
		const FHyperTwistTrainingRunState& ActiveRunState,
		const FHyperTwistTrainingCoachMemorySnapshot& CoachMemorySnapshot,
		int32 MaxCases
	)
	{
		const FResolvedCoachCaseBudget ResolvedBudget = QueueEntry.FocusCaseIds.Num() > 0
			? FResolvedCoachCaseBudget{
				FMath::Max(1, QueueEntry.FocusCaseIds.Num()),
				MaxCases > 0 ? FMath::Min(QueueEntry.FocusCaseIds.Num(), MaxCases) : QueueEntry.FocusCaseIds.Num(),
				FString()
			}
			: ResolvePreferredCoachCaseBudget(
				MaxCases,
				GuidanceLaneFromQueueSourceLabel(QueueEntry.SourceLabel),
				CoachMemorySnapshot,
				true
			);
		FHyperTwistTrainingDeck SourceDeck;
		if (!QueueEntry.FocusDeckId.IsEmpty())
		{
			UHyperTwistTrainingCatalogLibrary::TryFindDeckInCatalog(
				UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog(),
				QueueEntry.FocusDeckId,
				SourceDeck
			);
		}

		if (!SourceDeck.IsStructurallyValid()
			&& ActiveRunState.ActiveDeck.IsStructurallyValid()
			&& (QueueEntry.FocusDeckId.IsEmpty()
				|| QueueEntry.FocusDeckId == ActiveRunState.ActiveDeck.DeckId))
		{
			SourceDeck = ActiveRunState.ActiveDeck;
		}

		if (!SourceDeck.IsStructurallyValid())
		{
			return FHyperTwistTrainingDeck();
		}

		TArray<FHyperTwistTrainingCase> SelectedCases;
		if (QueueEntry.FocusCaseIds.Num() > 0)
		{
			for (const FString& FocusCaseId : QueueEntry.FocusCaseIds)
			{
				const FHyperTwistTrainingCase* MatchingCase = SourceDeck.Cases.FindByPredicate(
					[&FocusCaseId](const FHyperTwistTrainingCase& Candidate)
					{
						return Candidate.CaseId == FocusCaseId;
					}
				);
				if (MatchingCase != nullptr)
				{
					SelectedCases.Add(*MatchingCase);
					if (SelectedCases.Num() >= ResolvedBudget.ResolvedCaseCount)
					{
						break;
					}
				}
			}
		}

		if (SelectedCases.Num() == 0)
		{
			for (const FHyperTwistTrainingCase& Candidate : SourceDeck.Cases)
			{
				SelectedCases.Add(Candidate);
				if (SelectedCases.Num() >= ResolvedBudget.ResolvedCaseCount)
				{
					break;
				}
			}
		}

		if (SelectedCases.Num() == 0)
		{
			return FHyperTwistTrainingDeck();
		}

		FHyperTwistTrainingDeck FocusDeck = SourceDeck;
		FocusDeck.Cases = MoveTemp(SelectedCases);
		FocusDeck.SelectionPolicy = QueueEntry.SuggestedSelectionPolicy;
		if (QueueEntry.SuggestedMode != EHyperTwistTrainingDeliveryMode::Timer
			&& !FocusDeck.DeliveryModes.Contains(QueueEntry.SuggestedMode))
		{
			FocusDeck.DeliveryModes.Insert(QueueEntry.SuggestedMode, 0);
		}
		if (!QueueEntry.Headline.IsEmpty())
		{
			FocusDeck.Title = FString::Printf(TEXT("%s - %s"), *SourceDeck.Title, *QueueEntry.Headline);
		}
		if (!FocusDeck.Tags.Contains(TEXT("coach-queue")))
		{
			FocusDeck.Tags.Add(TEXT("coach-queue"));
		}
		if (!QueueEntry.SourceLabel.IsEmpty())
		{
			FocusDeck.Tags.AddUnique(FString::Printf(TEXT("coach-queue:%s"), *QueueEntry.SourceLabel.ToLower()));
		}
		if (!QueueEntry.FocusMethodSegmentId.IsEmpty())
		{
			FocusDeck.SubsetId = QueueEntry.FocusMethodSegmentId;
		}
		return FocusDeck;
	}

	bool IsLiveReviewPlanEntryState(const EHyperTwistTrainingReviewPlanEntryState EntryState)
	{
		return EntryState == EHyperTwistTrainingReviewPlanEntryState::Current
			|| EntryState == EHyperTwistTrainingReviewPlanEntryState::NeedsRepeat
			|| EntryState == EHyperTwistTrainingReviewPlanEntryState::Pending;
	}

	FHyperTwistTrainingDeck BuildReviewDeckFromPlan(
		const FHyperTwistTrainingDeck& SourceDeck,
		const FHyperTwistTrainingReviewPlanState& ReviewPlan,
		int32 MaxCases
	)
	{
		FHyperTwistTrainingDeck ReviewDeck;
		if (!SourceDeck.IsStructurallyValid() || !ReviewPlan.IsStructurallyValid() || ReviewPlan.bCompleted)
		{
			return ReviewDeck;
		}

		ReviewDeck = SourceDeck;
		ReviewDeck.DeckId = !ReviewPlan.ReviewDeckId.IsEmpty()
			? ReviewPlan.ReviewDeckId
			: SourceDeck.DeckId + TEXT("/review");
		ReviewDeck.Title = SourceDeck.Title + TEXT(" Review");
		ReviewDeck.SelectionPolicy = EHyperTwistTrainingSelectionPolicy::Spaced;
		ReviewDeck.Tags = SourceDeck.Tags;
		ReviewDeck.Tags.AddUnique(TEXT("review"));
		ReviewDeck.Tags.AddUnique(TEXT("review-plan-carryover"));
		ReviewDeck.Cases.Reset();
		if (ReviewPlan.DeliveryMode != EHyperTwistTrainingDeliveryMode::Timer
			&& !ReviewDeck.DeliveryModes.Contains(ReviewPlan.DeliveryMode))
		{
			ReviewDeck.DeliveryModes.Insert(ReviewPlan.DeliveryMode, 0);
		}

		const int32 EffectiveMaxCases = MaxCases > 0 ? MaxCases : ReviewPlan.Entries.Num();
		TSet<FString> AddedCaseIds;
		const auto TryAddCaseById = [&SourceDeck, &ReviewDeck, &AddedCaseIds, EffectiveMaxCases](
			const FString& CaseId
		) -> bool
		{
			if (CaseId.IsEmpty() || AddedCaseIds.Contains(CaseId))
			{
				return false;
			}

			const FHyperTwistTrainingCase* MatchingCase = SourceDeck.Cases.FindByPredicate(
				[&CaseId](const FHyperTwistTrainingCase& Candidate)
				{
					return Candidate.CaseId == CaseId;
				}
			);
			if (MatchingCase == nullptr)
			{
				return false;
			}

			ReviewDeck.Cases.Add(*MatchingCase);
			AddedCaseIds.Add(CaseId);
			return ReviewDeck.Cases.Num() >= EffectiveMaxCases;
		};

		int32 CurrentEntryIndex = ReviewPlan.CurrentEntryIndex;
		if (!ReviewPlan.Entries.IsValidIndex(CurrentEntryIndex))
		{
			CurrentEntryIndex = ReviewPlan.Entries.IndexOfByPredicate(
				[](const FHyperTwistTrainingReviewPlanEntry& Entry)
				{
					return Entry.EntryState == EHyperTwistTrainingReviewPlanEntryState::Current;
				}
			);
		}
		if (ReviewPlan.Entries.IsValidIndex(CurrentEntryIndex)
			&& IsLiveReviewPlanEntryState(ReviewPlan.Entries[CurrentEntryIndex].EntryState)
			&& TryAddCaseById(ReviewPlan.Entries[CurrentEntryIndex].CaseId))
		{
			return ReviewDeck;
		}

		for (const FHyperTwistTrainingReviewPlanEntry& Entry : ReviewPlan.Entries)
		{
			if (!IsLiveReviewPlanEntryState(Entry.EntryState))
			{
				continue;
			}

			if (TryAddCaseById(Entry.CaseId))
			{
				break;
			}
		}

		return ReviewDeck.Cases.Num() > 0 ? ReviewDeck : FHyperTwistTrainingDeck();
	}

	FHyperTwistTrainingReviewPolicy BuildTemplateReviewPolicy(
		const FHyperTwistTrainingSessionTemplate& SessionTemplate,
		int32 CaseCount
	);

	TArray<FHyperTwistTrainingCaseRecommendation> BuildTemplateReviewRecommendations(
		const FHyperTwistTrainingRepositoryState& RepositoryState,
		const FHyperTwistTrainingDeck& SourceDeck,
		const FHyperTwistTrainingDeck& ReviewDeck,
		const FString& UserId,
		const FHyperTwistTrainingSessionTemplate& SessionTemplate
	);

	bool ShouldResumeStoredReviewPlanFromTemplate(
		const FHyperTwistTrainingSessionTemplate& SessionTemplate,
		const FHyperTwistTrainingReviewPlanState& ReviewPlan,
		const FString& UserId
	)
	{
		if (!SessionTemplate.bPreferReviewRun
			|| !ReviewPlan.IsStructurallyValid()
			|| ReviewPlan.bCompleted)
		{
			return false;
		}
		if (!UserId.IsEmpty() && ReviewPlan.UserId != UserId)
		{
			return false;
		}
		if (SessionTemplate.SourceReviewPlanId.IsEmpty()
			|| SessionTemplate.SourceReviewPlanId != ReviewPlan.PlanId)
		{
			return false;
		}
		if (!SessionTemplate.FocusDeckId.IsEmpty()
			&& SessionTemplate.FocusDeckId != ReviewPlan.SourceDeckId)
		{
			return false;
		}

		return true;
	}

	FHyperTwistCoachBrief BuildCarryoverReviewResumeBrief(
		const FHyperTwistTrainingReviewPlanState& ReviewPlan,
		const FHyperTwistTrainingCoachActionPlan& CarryForwardActionPlan,
		const FHyperTwistCoachBrief& CurrentBrief,
		const FHyperTwistCoachBrief& FollowUpBrief,
		const FHyperTwistTrainingDeck& ReviewDeck
	)
	{
		FHyperTwistCoachBrief Brief = !FollowUpBrief.UserId.IsEmpty() ? FollowUpBrief : CurrentBrief;
		const TArray<FString> ReviewCaseIds = ExtractCaseIdsFromDeck(ReviewDeck);

		if (Brief.UserId.IsEmpty())
		{
			Brief.UserId = !ReviewPlan.UserId.IsEmpty() ? ReviewPlan.UserId : CarryForwardActionPlan.UserId;
		}
		if (Brief.ReferenceUtc.IsEmpty())
		{
			Brief.ReferenceUtc = !ReviewPlan.ReferenceUtc.IsEmpty()
				? ReviewPlan.ReferenceUtc
				: CarryForwardActionPlan.ReferenceUtc;
		}
		if (Brief.TrainingSessionId.IsEmpty())
		{
			Brief.TrainingSessionId = CarryForwardActionPlan.SourceSessionId;
		}
		if (Brief.SourceReviewPlanId.IsEmpty())
		{
			Brief.SourceReviewPlanId = ReviewPlan.PlanId;
		}
		if (Brief.CarryForwardPlanId.IsEmpty())
		{
			Brief.CarryForwardPlanId = CarryForwardActionPlan.PlanId;
		}
		if (Brief.RootPlanId.IsEmpty())
		{
			Brief.RootPlanId = !CarryForwardActionPlan.RootPlanId.IsEmpty()
				? CarryForwardActionPlan.RootPlanId
				: CarryForwardActionPlan.PlanId;
		}
		Brief.FollowUpDepth = FMath::Max(Brief.FollowUpDepth, CarryForwardActionPlan.FollowUpDepth + 1);
		if (Brief.FocusDeckId.IsEmpty())
		{
			Brief.FocusDeckId = !ReviewPlan.SourceDeckId.IsEmpty()
				? ReviewPlan.SourceDeckId
				: (!CarryForwardActionPlan.FocusDeckId.IsEmpty()
					? CarryForwardActionPlan.FocusDeckId
					: ReviewDeck.DeckId);
		}
		if (Brief.FocusMethodSegmentId.IsEmpty())
		{
			Brief.FocusMethodSegmentId = CarryForwardActionPlan.FocusMethodSegmentId;
		}
		if (ReviewCaseIds.Num() > 0)
		{
			Brief.FocusCaseIds = ReviewCaseIds;
		}
		if (Brief.Headline.IsEmpty())
		{
			Brief.Headline = CarryForwardActionPlan.Headline.IsEmpty()
				? TEXT("Resume review carryover")
				: FString::Printf(TEXT("%s (carryover review)"), *CarryForwardActionPlan.Headline);
		}
		if (Brief.PrimaryActionLabel.IsEmpty())
		{
			Brief.PrimaryActionLabel = TEXT("resume_review_plan");
		}
		Brief.SuggestedMode = ReviewPlan.DeliveryMode;
		Brief.SuggestedSelectionPolicy = ReviewDeck.SelectionPolicy;
		if (Brief.FocusLane == EHyperTwistCoachFocusLane::Stability)
		{
			Brief.FocusLane = EHyperTwistCoachFocusLane::ReviewBacklog;
		}
		if (Brief.PriorityScore <= 0.0f)
		{
			Brief.PriorityScore = CarryForwardActionPlan.PriorityScore > 0.0f
				? CarryForwardActionPlan.PriorityScore
				: 60.0f;
		}
		if (Brief.Priority == EHyperTwistCoachPriority::Informational && Brief.PriorityScore > 0.0f)
		{
			Brief.Priority = CoachPriorityFromScore(Brief.PriorityScore);
		}
		Brief.bNeedsCoachReview = Brief.bNeedsCoachReview || CarryForwardActionPlan.bNeedsCoachReview;
		Brief.bNeedsCadenceRecovery =
			Brief.bNeedsCadenceRecovery || CarryForwardActionPlan.bNeedsCadenceRecovery;
		Brief.bNeedsVarietyRotation =
			Brief.bNeedsVarietyRotation || CarryForwardActionPlan.bNeedsVarietyRotation;
		Brief.bPreferRecognitionReplayReview =
			Brief.bPreferRecognitionReplayReview
			|| CarryForwardActionPlan.bPreferRecognitionReplayReview
			|| ReviewPlan.DeliveryMode == EHyperTwistTrainingDeliveryMode::RecognitionAssisted;
		return Brief;
	}

	bool TryPrepareReviewPlanBackedTemplateLaunch(
		const FHyperTwistTrainingRepositoryState& RepositoryState,
		const FHyperTwistTrainingSessionTemplate& SessionTemplate,
		const FHyperTwistTrainingDeck& ReviewDeck,
		const FString& UserId,
		FHyperTwistTrainingDeck& OutSourceDeck,
		FHyperTwistTrainingReviewPolicy& OutReviewPolicy,
		TArray<FHyperTwistTrainingCaseRecommendation>& OutRecommendations
	)
	{
		OutSourceDeck = FHyperTwistTrainingDeck();
		OutReviewPolicy = FHyperTwistTrainingReviewPolicy();
		OutRecommendations.Reset();
		if (!SessionTemplate.bPreferReviewRun || !ReviewDeck.IsStructurallyValid() || UserId.IsEmpty())
		{
			return false;
		}
		if (!UHyperTwistTrainingCatalogLibrary::TryFindDeckInCatalog(
				UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog(),
				SessionTemplate.FocusDeckId,
				OutSourceDeck))
		{
			return false;
		}

		OutReviewPolicy = BuildTemplateReviewPolicy(SessionTemplate, ReviewDeck.Cases.Num());
		OutRecommendations = BuildTemplateReviewRecommendations(
			RepositoryState,
			OutSourceDeck,
			ReviewDeck,
			UserId,
			SessionTemplate
		);
		return OutSourceDeck.IsStructurallyValid();
	}

	FHyperTwistTrainingReviewPolicy BuildTemplateReviewPolicy(
		const FHyperTwistTrainingSessionTemplate& SessionTemplate,
		int32 CaseCount
	)
	{
		FHyperTwistTrainingReviewPolicy ReviewPolicy =
			UHyperTwistTrainingRepositoryLibrary::GetDefaultReviewPolicy(SessionTemplate.SuggestedMode);
		ReviewPolicy.MaxCases = CaseCount > 0 ? CaseCount : ReviewPolicy.MaxCases;
		ReviewPolicy.bPreferShortReviewSets =
			ReviewPolicy.bPreferShortReviewSets
			|| SessionTemplate.bPreferShortReviewSet
			|| (CaseCount > 0 && CaseCount <= 4);
		return ReviewPolicy;
	}

	TArray<FHyperTwistTrainingCaseRecommendation> BuildTemplateReviewRecommendations(
		const FHyperTwistTrainingRepositoryState& RepositoryState,
		const FHyperTwistTrainingDeck& SourceDeck,
		const FHyperTwistTrainingDeck& ReviewDeck,
		const FString& UserId,
		const FHyperTwistTrainingSessionTemplate& SessionTemplate
	)
	{
		const TArray<FHyperTwistTrainingCaseRecommendation> SourceRecommendations =
			UHyperTwistTrainingRepositoryLibrary::ListCaseRecommendationsForDeck(
				RepositoryState,
				SourceDeck,
				UserId,
				FString(),
				SourceDeck.Cases.Num()
			);
		TMap<FString, FHyperTwistTrainingCaseRecommendation> RecommendationByCaseId;
		for (const FHyperTwistTrainingCaseRecommendation& Recommendation : SourceRecommendations)
		{
			if (Recommendation.IsStructurallyValid())
			{
				RecommendationByCaseId.Add(Recommendation.TrainingCase.CaseId, Recommendation);
			}
		}

		TArray<FHyperTwistTrainingCaseRecommendation> OrderedRecommendations;
		OrderedRecommendations.Reserve(ReviewDeck.Cases.Num());
		const FString DefaultReason = !SessionTemplate.GuidanceLabel.IsEmpty()
			? SessionTemplate.GuidanceLabel
			: (SessionTemplate.bCoachReview ? TEXT("coach-review-template") : TEXT("review-template"));
		const FString ReferenceUtc = !SessionTemplate.LastUpdatedAtUtc.IsEmpty()
			? SessionTemplate.LastUpdatedAtUtc
			: FDateTime::UtcNow().ToIso8601();
		for (int32 CaseIndex = 0; CaseIndex < ReviewDeck.Cases.Num(); ++CaseIndex)
		{
			const FHyperTwistTrainingCase& TrainingCase = ReviewDeck.Cases[CaseIndex];
			if (!TrainingCase.IsStructurallyValid())
			{
				continue;
			}

			FHyperTwistTrainingCaseRecommendation OrderedRecommendation;
			if (const FHyperTwistTrainingCaseRecommendation* MatchingRecommendation =
				RecommendationByCaseId.Find(TrainingCase.CaseId))
			{
				OrderedRecommendation = *MatchingRecommendation;
			}

			OrderedRecommendation.TrainingCase = TrainingCase;
			if (OrderedRecommendation.ReferenceUtc.IsEmpty())
			{
				OrderedRecommendation.ReferenceUtc = ReferenceUtc;
			}
			if (OrderedRecommendation.RecommendationReason.IsEmpty())
			{
				OrderedRecommendation.RecommendationReason = DefaultReason;
			}
			if (OrderedRecommendation.RecommendationScore <= -999.0f)
			{
				OrderedRecommendation.RecommendationScore = 1000.0f - static_cast<float>(CaseIndex);
			}
			OrderedRecommendations.Add(OrderedRecommendation);
		}

		return OrderedRecommendations;
	}

	FHyperTwistCoachBrief BuildCoachBriefFromQueueEntry(
		const FHyperTwistTrainingCoachSessionQueueState& QueueState,
		const FHyperTwistTrainingCoachSessionQueueStateEntry& QueueEntry,
		const FString& ReferenceUtc
	)
	{
		FHyperTwistCoachBrief Brief;
		Brief.UserId = QueueState.UserId;
		Brief.ReferenceUtc = ReferenceUtc;
		Brief.TrainingSessionId = QueueEntry.SourceBriefTrainingSessionId;
		Brief.SourceReviewPlanId = QueueEntry.SourceReviewPlanId;
		Brief.CarryForwardPlanId = QueueEntry.CarryForwardPlanId;
		Brief.RootPlanId = !QueueEntry.RootPlanId.IsEmpty()
			? QueueEntry.RootPlanId
			: QueueEntry.CarryForwardPlanId;
		Brief.FollowUpDepth = FMath::Max(0, QueueEntry.FollowUpDepth);
		Brief.PriorityScore = QueueEntry.PriorityScore;
		Brief.Priority = CoachPriorityFromScore(QueueEntry.PriorityScore);
		Brief.FocusLane = QueueEntry.SourceLabel == TEXT("archive-policy")
			? EHyperTwistCoachFocusLane::Stability
			: EnumValueFromName(
				QueueEntry.FocusLaneLabel,
				EHyperTwistCoachFocusLane::ReviewBacklog
			);
		Brief.Headline = QueueEntry.Headline;
		Brief.PrimaryActionLabel = !QueueEntry.PrimaryActionLabel.IsEmpty()
			? QueueEntry.PrimaryActionLabel
			: ResolveQueueActionLabel(QueueEntry.SourceLabel);
		Brief.SuggestedMode = QueueEntry.SuggestedMode;
		Brief.SuggestedSelectionPolicy = QueueEntry.SuggestedSelectionPolicy;
		Brief.FocusDeckId = QueueEntry.FocusDeckId;
		Brief.FocusMethodSegmentId = QueueEntry.FocusMethodSegmentId;
		Brief.FocusCaseIds = QueueEntry.FocusCaseIds;
		Brief.DeferredLaunchCaseCount = FMath::Max(0, QueueEntry.DeferredLaunchCaseCount);
		Brief.bNeedsDeferredLaunchRecovery = QueueEntry.bNeedsDeferredLaunchRecovery;
		Brief.bHasTightenedLaunchOverflow = QueueEntry.bHasTightenedLaunchOverflow;
		Brief.bNeedsCoachReview = QueueEntry.bNeedsCoachReview;
		Brief.bNeedsCadenceRecovery = QueueEntry.bNeedsCadenceRecovery;
		Brief.bNeedsVarietyRotation = QueueEntry.bNeedsVarietyRotation;
		Brief.bPreferRecognitionReplayReview = QueueEntry.bPreferRecognitionReplayReview;
		return Brief;
	}

	template <typename TStruct>
	bool SerializeStruct(const TStruct& Value, FString& OutJson)
	{
		return FJsonObjectConverter::UStructToJsonObjectString(TStruct::StaticStruct(), &Value, OutJson, 0, 0);
	}

	template <typename TStruct>
	bool DeserializeStruct(const FString& Json, TStruct& OutValue)
	{
		return !Json.IsEmpty() && FJsonObjectConverter::JsonObjectStringToUStruct(Json, &OutValue, 0, 0);
	}

	IHyperTwistVisionClient* ResolveVisionClient(UObject* Candidate)
	{
		return Candidate != nullptr && Candidate->GetClass()->ImplementsInterface(UHyperTwistVisionClient::StaticClass())
			? Cast<IHyperTwistVisionClient>(Candidate)
			: nullptr;
	}

	FString BuildRecognitionSessionId(const FHyperTwistTrainingSession& Session, const int32 SessionOrdinal)
	{
		const int32 ResolvedOrdinal = FMath::Max(1, SessionOrdinal);
		return FString::Printf(TEXT("%s_recognition_%02d"), *Session.TrainingSessionId, ResolvedOrdinal);
	}

	FString BuildRecognitionFrameId(const FString& SessionId, const int32 FrameOrdinal)
	{
		return FString::Printf(TEXT("%s_frame_%03d"), *SessionId, FMath::Max(1, FrameOrdinal));
	}

	EHyperTwistPuzzleFamily ResolvePuzzleFamilyFromPuzzleId(const FString& PuzzleId)
	{
		if (PuzzleId.StartsWith(TEXT("hypercube/")))
		{
			return EHyperTwistPuzzleFamily::Hypercube;
		}
		if (PuzzleId.StartsWith(TEXT("cube/")))
		{
			return EHyperTwistPuzzleFamily::ClassicCube;
		}
		return EHyperTwistPuzzleFamily::Other;
	}

	FString ResolveNotationProfileFromPuzzleId(const FString& PuzzleId)
	{
		if (PuzzleId.StartsWith(TEXT("hypercube/")))
		{
			return TEXT("hyper-4d");
		}
		return TEXT("classic-wca");
	}

	bool IsRecognitionReplayEventType(const EHyperTwistReplayEventType EventType)
	{
		return EventType == EHyperTwistReplayEventType::RecognitionPreview
			|| EventType == EHyperTwistReplayEventType::RecognitionScan
			|| EventType == EHyperTwistReplayEventType::RecognitionCommit
			|| EventType == EHyperTwistReplayEventType::RecognitionCorrection;
	}

	FHyperTwistReplayRecognitionPayload BuildFinalizeCorrectionPayload(
		const FHyperTwistVisionFinalizeResult& FinalizeResult
	)
	{
		FHyperTwistReplayRecognitionPayload Payload;
		Payload.Snapshot = FinalizeResult.FinalSnapshot;
		Payload.Confidence = FinalizeResult.ConfidenceRollup;
		return Payload;
	}

	FHyperTwistReplayRecognitionPayload BuildFinalizeCommitPayload(
		const FHyperTwistVisionFinalizeResult& FinalizeResult
	)
	{
		FHyperTwistReplayRecognitionPayload Payload;
		Payload.Snapshot = FinalizeResult.FinalSnapshot;
		Payload.Confidence = FinalizeResult.ConfidenceRollup;
		return Payload;
	}

	FHyperTwistStateSnapshot BuildSnapshotFromFinalState(
		const FHyperTwistVisionFinalizeResult& FinalizeResult
	)
	{
		FHyperTwistStateSnapshot Snapshot = FinalizeResult.FinalSnapshot;
		if (Snapshot.SnapshotId.IsEmpty())
		{
			Snapshot.SnapshotId = FString::Printf(TEXT("recognition_final_%s"), *FinalizeResult.SessionId);
		}
		if (!Snapshot.State.IsStructurallyValid() && FinalizeResult.FinalState.IsStructurallyValid())
		{
			Snapshot.State = FinalizeResult.FinalState;
		}
		if (Snapshot.DerivedHash.IsEmpty())
		{
			Snapshot.DerivedHash = FString::Printf(TEXT("recognition-final-%s"), *FinalizeResult.SessionId);
		}
		return Snapshot;
	}

	int32 CountRecognitionCorrectionEvents(const TArray<FHyperTwistReplayEvent>& Events)
	{
		int32 Count = 0;
		for (const FHyperTwistReplayEvent& Event : Events)
		{
			if (Event.EventType == EHyperTwistReplayEventType::RecognitionCorrection)
			{
				++Count;
			}
		}
		return Count;
	}

	FString FormatRecognitionConfidence(const float Value)
	{
		return Value >= 0.0f ? FString::Printf(TEXT("%.2f"), Value) : TEXT("n/a");
	}
}

bool UHyperTwistTrainingSubsystem::HasActiveRun() const
{
	return bHasActiveRun && ActiveRunState.IsStructurallyValid();
}

bool UHyperTwistTrainingSubsystem::HasActiveMethodDrillRun() const
{
	return bHasActiveMethodDrillRun && ActiveMethodDrillRunState.IsStructurallyValid();
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::GetActiveRunState() const
{
	return ActiveRunState;
}

bool UHyperTwistTrainingSubsystem::HasActiveLiveTimer() const
{
	return HasActiveRun()
		&& ActiveRunState.Session.IsStructurallyValid()
		&& ActiveLiveTimerState.IsActive()
		&& ActiveLiveTimerState.TrainingSessionId == ActiveRunState.Session.TrainingSessionId
		&& ActiveLiveTimerState.CaseId == ActiveRunState.CurrentSelection.TrainingCase.CaseId;
}

FHyperTwistTrainingLiveTimerState UHyperTwistTrainingSubsystem::GetActiveLiveTimerState()
{
	RefreshActiveLiveTimerState();
	return ActiveLiveTimerState;
}

bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSurface(
	FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface
) const
{
	return UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
		ActiveRunState.ActiveDeck,
		OutRuntimeSurface
	);
}

bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSelector(
	const FString& SelectorId,
	FHyperTwistTrainingImportedRuntimeSelector& OutSelector
) const
{
	return UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorFromDeck(
		ActiveRunState.ActiveDeck,
		SelectorId,
		OutSelector
	);
}

bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSelectorOptionCases(
	const FString& SelectorId,
	TArray<FHyperTwistTrainingCase>& OutCases
) const
{
	return UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorOptionCasesFromDeck(
		ActiveRunState.ActiveDeck,
		SelectorId,
		OutCases
	);
}

bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSelectionState(
	FHyperTwistTrainingImportedRuntimeSelectionState& OutSelectionState
) const
{
	OutSelectionState = FHyperTwistTrainingImportedRuntimeSelectionState();
	if (!HasActiveRun() || !ActiveRunState.ImportedRuntimeSelectionState.IsStructurallyValid())
	{
		return false;
	}

	OutSelectionState = ActiveRunState.ImportedRuntimeSelectionState;
	return OutSelectionState.IsStructurallyValid();
}

bool UHyperTwistTrainingSubsystem::TryGetActiveImportedGeneratedModeLaunchConfig(
	FHyperTwistTrainingImportedGeneratedModeLaunchConfig& OutLaunchConfig
) const
{
	return UHyperTwistTrainingCatalogLibrary::TryBuildImportedGeneratedModeLaunchConfig(
		ActiveRunState.ActiveDeck,
		ActiveRunState.ImportedRuntimeSelectionState,
		ActiveRunState.Session,
		OutLaunchConfig
	);
}

bool UHyperTwistTrainingSubsystem::TryGetActiveImportedGeneratedModeLaunchRequest(
	FHyperTwistTrainingImportedGeneratedModeLaunchRequest& OutLaunchRequest
) const
{
	OutLaunchRequest = ActiveImportedGeneratedModeLaunchRequest;
	return OutLaunchRequest.IsStructurallyValid();
}

FHyperTwistTrainingImportedGeneratedModeLaunchRequest UHyperTwistTrainingSubsystem::CreateActiveImportedGeneratedModeLaunchRequest(
	const FString& RequestSource
)
{
	FHyperTwistTrainingImportedGeneratedModeLaunchConfig LaunchConfig;
	if (!TryGetActiveImportedGeneratedModeLaunchConfig(LaunchConfig))
	{
		ActiveImportedGeneratedModeLaunchRequest = FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
		return ActiveImportedGeneratedModeLaunchRequest;
	}

	ActiveImportedGeneratedModeLaunchRequest = FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
	ActiveImportedGeneratedModeLaunchRequest.RequestId =
		FString::Printf(TEXT("generated_launch_%s"), *FGuid::NewGuid().ToString(EGuidFormats::Digits));
	ActiveImportedGeneratedModeLaunchRequest.RequestedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveImportedGeneratedModeLaunchRequest.RequestSource =
		RequestSource.IsEmpty() ? TEXT("runtime-imported-generated-mode") : RequestSource;
	ActiveImportedGeneratedModeLaunchRequest.LaunchConfig = LaunchConfig;
    ActiveRunState.ImportedGeneratedModeLaunchRequest = ActiveImportedGeneratedModeLaunchRequest;
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	RefreshRepositoryViews();
	return ActiveImportedGeneratedModeLaunchRequest;
}

bool UHyperTwistTrainingSubsystem::TryExecuteActiveImportedGeneratedModeLaunchRequest(
	FHyperTwistTrainingRunState& OutRunState,
	FString& OutBlockedReason
)
{
	OutRunState = FHyperTwistTrainingRunState();
	OutBlockedReason.Reset();

	if (!HasActiveRun())
	{
		OutBlockedReason = TEXT("Generated-mode execution requires an active training run.");
		return false;
	}

	FHyperTwistTrainingImportedGeneratedModeLaunchConfig ExpectedLaunchConfig;
	FHyperTwistTrainingImportedGeneratedModeLaunchRequest LaunchRequest =
		ActiveImportedGeneratedModeLaunchRequest;
	bool bNeedsFreshLaunchRequest = false;
	if (!HyperTwistTrainingSubsystemInternal::TryResolveGeneratedModeExecutionLaunchConfig(
			ActiveRunState,
			LaunchRequest,
			ExpectedLaunchConfig,
			bNeedsFreshLaunchRequest,
			OutBlockedReason))
	{
		return false;
	}

	if (bNeedsFreshLaunchRequest)
	{
		LaunchRequest = CreateActiveImportedGeneratedModeLaunchRequest(
			TEXT("runtime-imported-generated-mode-executor")
		);
	}
	if (!LaunchRequest.IsStructurallyValid())
	{
		OutBlockedReason = TEXT("Generated-mode execution could not derive a structurally valid launch request.");
		return false;
	}
	if (!UHyperTwistTrainingCatalogLibrary::TryBuildImportedGeneratedModeLaunchConfig(
			ActiveRunState.ActiveDeck,
			ActiveRunState.ImportedRuntimeSelectionState,
			ActiveRunState.Session,
			ExpectedLaunchConfig))
	{
		OutBlockedReason =
			TEXT("Generated-mode execution could not derive a structurally valid launch request from the active selector state.");
		return false;
	}
	FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
	if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
			ActiveRunState.ActiveDeck,
			RuntimeSurface)
		|| !HyperTwistTrainingSubsystemInternal::DoesGeneratedModeLaunchRequestMatchLaunchConfig(
			LaunchRequest,
			RuntimeSurface,
			ExpectedLaunchConfig))
	{
		OutBlockedReason =
			TEXT("Generated-mode execution could not persist a launch request that matched the active selector state.");
		return false;
	}

	const FHyperTwistTrainingRunState SourceRunState = ActiveRunState;
	FHyperTwistTrainingDeck GeneratedDeck;
	if (!HyperTwistTrainingSubsystemInternal::TryBuildGeneratedModeExecutionDeck(
			SourceRunState.ActiveDeck,
			LaunchRequest,
			GeneratedDeck,
			OutBlockedReason))
	{
		return false;
	}

	const FString ExecutionSessionId =
		HyperTwistTrainingSubsystemInternal::BuildGeneratedModeExecutionSessionId(LaunchRequest);
	const FHyperTwistTrainingRunState StartedRunState = StartTrainingRunFromDeck(
		GeneratedDeck,
		SourceRunState.Session.UserId,
		ExecutionSessionId,
		LaunchRequest.LaunchConfig.DeliveryMode
	);
	if (!StartedRunState.IsStructurallyValid())
	{
		OutBlockedReason = TEXT("Generated-mode executor could not start a structurally valid owned run.");
		return false;
	}

	ActiveRunState.ImportedRuntimeSelectionState = SourceRunState.ImportedRuntimeSelectionState;
	ActiveImportedGeneratedModeLaunchRequest = LaunchRequest;
	ActiveRunState.ImportedGeneratedModeLaunchRequest = LaunchRequest;
	RefreshSummary();
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	RefreshRepositoryViews();

	OutRunState = ActiveRunState;
	return OutRunState.IsStructurallyValid();
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::ApplyActiveImportedRuntimeSelectorOption(
	const FString& SelectorId,
	const FString& OptionId
)
{
	if (!HasActiveRun())
	{
		return FHyperTwistTrainingRunState();
	}

	FHyperTwistTrainingCase SelectedCase;
	if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorOptionCaseFromDeck(
			ActiveRunState.ActiveDeck,
			SelectorId,
			OptionId,
			SelectedCase))
	{
		return FHyperTwistTrainingRunState();
	}

	FHyperTwistTrainingDeck SelectedDeck = ActiveRunState.ActiveDeck;
	SelectedDeck.SelectionPolicy = EHyperTwistTrainingSelectionPolicy::Scripted;
	SelectedDeck.Cases.Reset();
	SelectedDeck.Cases.Add(SelectedCase);
	SelectedDeck.Tags.AddUnique(TEXT("runtime-surface:selector-option-applied"));
	SelectedDeck.Tags.AddUnique(FString::Printf(TEXT("selector:%s"), *SelectorId.ToLower()));
	SelectedDeck.Tags.AddUnique(FString::Printf(TEXT("selector-option:%s"), *OptionId.ToLower()));

	return StartTrainingRunFromDeck(
		SelectedDeck,
		ActiveRunState.Session.UserId,
		ActiveRunState.Session.TrainingSessionId,
		ActiveRunState.Session.Mode
	);
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::ApplyActiveImportedGeneratedModeSelectorChoice(
	const FString& SelectorId,
	const FString& SelectedValue,
	const FString& DisplayValue
)
{
	if (!HasActiveRun() || SelectedValue.IsEmpty())
	{
		return FHyperTwistTrainingRunState();
	}

	FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
	if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
			ActiveRunState.ActiveDeck,
			RuntimeSurface)
		|| !RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
	{
		return FHyperTwistTrainingRunState();
	}

	FHyperTwistTrainingImportedRuntimeSelector Selector;
	if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorFromDeck(
			ActiveRunState.ActiveDeck,
			SelectorId,
			Selector))
	{
		return FHyperTwistTrainingRunState();
	}

	if (!ActiveRunState.ImportedRuntimeSelectionState.IsStructurallyValid())
	{
		ActiveRunState.ImportedRuntimeSelectionState.SurfaceId = RuntimeSurface.SurfaceId;
		ActiveRunState.ImportedRuntimeSelectionState.SurfaceKind = RuntimeSurface.SurfaceKind;
	}

	FHyperTwistTrainingImportedRuntimeSelectorChoice* ExistingChoice =
		ActiveRunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
			[&SelectorId](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
			{
				return Candidate.SelectorId == SelectorId;
			}
		);
	if (ExistingChoice != nullptr)
	{
		ExistingChoice->SelectorBinding = Selector.SelectorBinding;
		ExistingChoice->SelectedValue = SelectedValue;
		ExistingChoice->DisplayValue = DisplayValue.IsEmpty() ? SelectedValue : DisplayValue;
	}
	else
	{
		FHyperTwistTrainingImportedRuntimeSelectorChoice Choice;
		Choice.SelectorId = SelectorId;
		Choice.SelectorBinding = Selector.SelectorBinding;
		Choice.SelectedValue = SelectedValue;
		Choice.DisplayValue = DisplayValue.IsEmpty() ? SelectedValue : DisplayValue;
		ActiveRunState.ImportedRuntimeSelectionState.SelectorChoices.Add(MoveTemp(Choice));
	}

	ActiveRunState.ActiveDeck.Tags.AddUnique(TEXT("runtime-surface:generated-choice-applied"));
	ActiveRunState.ActiveDeck.Tags.AddUnique(FString::Printf(TEXT("selector:%s"), *SelectorId.ToLower()));
	ActiveRunState.ActiveDeck.Tags.AddUnique(FString::Printf(TEXT("selector-choice:%s"), *SelectedValue.ToLower()));
	RefreshSummary();
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	RefreshRepositoryViews();
	return ActiveRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::GetActiveMethodDrillRunState() const
{
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingSessionSummary UHyperTwistTrainingSubsystem::GetActiveRunSummary() const
{
	return ActiveRunSummary;
}

FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingSubsystem::GetActiveMethodDrillSummary() const
{
	return ActiveMethodDrillSummary;
}

FHyperTwistTrainingMethodDrillDiagnosticPacket UHyperTwistTrainingSubsystem::GetActiveMethodDrillDiagnosticPacket() const
{
	return ActiveMethodDrillDiagnosticPacket;
}

FHyperTwistTrainingSessionTemplate UHyperTwistTrainingSubsystem::GetActiveMethodDrillFollowUpTemplate() const
{
	return ActiveMethodDrillFollowUpTemplate;
}

FHyperTwistTrainingRepositoryState UHyperTwistTrainingSubsystem::GetTrainingRepositoryState() const
{
	return TrainingRepositoryState;
}

bool UHyperTwistTrainingSubsystem::RecordActiveRunTemplateLaunchSelectionProvenance(
	const FHyperTwistTrainingTemplateLaunchSelectionProvenance& SelectionProvenance
)
{
	if (!SelectionProvenance.IsStructurallyValid()
		|| !ActiveRunState.IsStructurallyValid()
		|| !ActiveRunState.TemplateLaunchProvenance.IsStructurallyValid())
	{
		return false;
	}

	ActiveRunState.TemplateLaunchProvenance.SelectionProvenance = SelectionProvenance;
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	return true;
}

bool UHyperTwistTrainingSubsystem::TryGetLatestGeneratedModeLaunchRequestForDeck(
	const FString& UserId,
	const FString& DeckId,
	FHyperTwistTrainingImportedGeneratedModeLaunchRequest& OutLaunchRequest
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetLatestGeneratedModeLaunchRequestForDeck(
		TrainingRepositoryState,
		UserId,
		DeckId,
		OutLaunchRequest
	);
}

bool UHyperTwistTrainingSubsystem::TryGetLatestGeneratedModeLaunchRequestForActiveDeck(
	FHyperTwistTrainingImportedGeneratedModeLaunchRequest& OutLaunchRequest
) const
{
	if (!HasActiveRun())
	{
		OutLaunchRequest = FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
		return false;
	}

	return TryGetLatestGeneratedModeLaunchRequestForDeck(
		ActiveRunState.Session.UserId,
		ActiveRunState.Session.DeckId,
		OutLaunchRequest
	);
}

FHyperTwistTrainingRepositoryIntegrityReport UHyperTwistTrainingSubsystem::GetActiveRepositoryIntegrityReport() const
{
	return ActiveRepositoryIntegrityReport;
}

FHyperTwistTrainingRepositoryRoundTripVerification
UHyperTwistTrainingSubsystem::GetActiveRepositoryRoundTripVerification() const
{
	return ActiveRepositoryRoundTripVerification;
}

FHyperTwistTrainingCoachPanelState UHyperTwistTrainingSubsystem::GetActiveCoachPanelState() const
{
	FHyperTwistTrainingCoachPanelState PanelState;
	PanelState.UserId = !ActiveCoachBrief.UserId.IsEmpty()
		? ActiveCoachBrief.UserId
		: (!ActiveCoachSessionQueueSummary.UserId.IsEmpty()
			? ActiveCoachSessionQueueSummary.UserId
			: ActiveRunState.Session.UserId);
	PanelState.bHasActiveRun = HasActiveRun();
	PanelState.bHasCoachGuidance = !ActiveCoachBrief.UserId.IsEmpty() && !ActiveCoachBrief.Headline.IsEmpty();
	PanelState.bHasFollowUpGuidance =
		!ActiveCoachFollowUpBrief.UserId.IsEmpty() && !ActiveCoachFollowUpBrief.Headline.IsEmpty();
	PanelState.SignalCount = ActiveCoachSignals.Num();
	PanelState.PreferredGuidanceLane = ActiveCoachMemorySnapshot.PreferredGuidanceLane;
	PanelState.PreferredGuidanceSourceLabel = ActiveCoachMemorySnapshot.PreferredGuidanceSourceLabel;
	PanelState.PreferredCoachHandoffKind = ActiveCoachMemorySnapshot.PreferredCoachHandoffKind;
	PanelState.PreferredCoachHandoffSourceLabel =
		ActiveCoachMemorySnapshot.PreferredCoachHandoffSourceLabel;
	PanelState.PreferredQueueRecoveryAction = ActiveCoachMemorySnapshot.PreferredQueueRecoveryAction;
	PanelState.PreferredQueueRecoveryActionSourceLabel =
		ActiveCoachMemorySnapshot.PreferredQueueRecoveryActionSourceLabel;
	PanelState.PreferredLaunchBudgetBias = ActiveCoachMemorySnapshot.PreferredLaunchBudgetBias;
	PanelState.PreferredLaunchBudgetSourceLabel =
		ActiveCoachMemorySnapshot.PreferredLaunchBudgetSourceLabel;
	PanelState.BroadenedLaunchBudgetHistoryCount =
		ActiveCoachMemorySnapshot.BroadenedLaunchBudgetHistoryCount;
	PanelState.TightenedLaunchBudgetHistoryCount =
		ActiveCoachMemorySnapshot.TightenedLaunchBudgetHistoryCount;
	PanelState.DeferredTightenedLaunchHistoryCount =
		ActiveCoachMemorySnapshot.DeferredTightenedLaunchHistoryCount;
	PanelState.DeferredLaunchHistoryCaseCount =
		ActiveCoachMemorySnapshot.DeferredLaunchHistoryCaseCount;
	PanelState.MethodDrillFollowUpHistoryCount =
		ActiveCoachMemorySnapshot.MethodDrillFollowUpHistoryCount;
	PanelState.StrongMethodDrillFollowUpHistoryCount =
		ActiveCoachMemorySnapshot.StrongMethodDrillFollowUpHistoryCount;
	PanelState.WeakMethodDrillFollowUpHistoryCount =
		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 =
		ActiveCoachMemorySnapshot.StrongMethodDrillRecoveryHistoryCount;
	PanelState.WeakMethodDrillRecoveryHistoryCount =
		ActiveCoachMemorySnapshot.WeakMethodDrillRecoveryHistoryCount;
	PanelState.MethodDrillRecoveryAverageOutcomeScore =
		ActiveCoachMemorySnapshot.MethodDrillRecoveryAverageOutcomeScore;
	PanelState.TrustedTightMethodDrillRecoveryStructurePlanHistoryCount =
		ActiveCoachMemorySnapshot.TrustedTightMethodDrillRecoveryStructurePlanHistoryCount;
	PanelState.TrustedBroadMethodDrillRecoveryStructurePlanHistoryCount =
		ActiveCoachMemorySnapshot.TrustedBroadMethodDrillRecoveryStructurePlanHistoryCount;
	PanelState.TrustedTightMethodDrillRecoveryStructurePlanAverageOutcomeScore =
		ActiveCoachMemorySnapshot.TrustedTightMethodDrillRecoveryStructurePlanAverageOutcomeScore;
	PanelState.TrustedBroadMethodDrillRecoveryStructurePlanAverageOutcomeScore =
		ActiveCoachMemorySnapshot.TrustedBroadMethodDrillRecoveryStructurePlanAverageOutcomeScore;
	PanelState.ReliableTrustedTightMethodDrillRecoveryStructurePlanHistoryCount =
		ActiveCoachMemorySnapshot.ReliableTrustedTightMethodDrillRecoveryStructurePlanHistoryCount;
	PanelState.ReliableTrustedBroadMethodDrillRecoveryStructurePlanHistoryCount =
		ActiveCoachMemorySnapshot.ReliableTrustedBroadMethodDrillRecoveryStructurePlanHistoryCount;
	PanelState.ReliableTrustedTightMethodDrillRecoveryStructurePlanAverageOutcomeScore =
		ActiveCoachMemorySnapshot.ReliableTrustedTightMethodDrillRecoveryStructurePlanAverageOutcomeScore;
	PanelState.ReliableTrustedBroadMethodDrillRecoveryStructurePlanAverageOutcomeScore =
		ActiveCoachMemorySnapshot.ReliableTrustedBroadMethodDrillRecoveryStructurePlanAverageOutcomeScore;
	PanelState.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanHistoryCount =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanHistoryCount;
	PanelState.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanHistoryCount =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanHistoryCount;
	PanelState.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanAverageOutcomeScore =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanAverageOutcomeScore;
	PanelState.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanAverageOutcomeScore =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanAverageOutcomeScore;
	PanelState.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanOutcomeHistoryCount =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanOutcomeHistoryCount;
	PanelState.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanOutcomeHistoryCount =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanOutcomeHistoryCount;
	PanelState.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanOutcomeAverageScore =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedTightMethodDrillRecoveryStructurePlanOutcomeAverageScore;
	PanelState.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanOutcomeAverageScore =
		ActiveCoachMemorySnapshot
			.ReliableAlignedTrustedBroadMethodDrillRecoveryStructurePlanOutcomeAverageScore;
	PanelState.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeHistoryCount;
	PanelState.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeHistoryCount;
	PanelState.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeAverageScore =
		ActiveCoachMemorySnapshot.ReliableAlignedTrustedTightFollowUpGuidanceOutcomeAverageScore;
	PanelState.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore =
		ActiveCoachMemorySnapshot.ReliableAlignedTrustedBroadRecommendedGuidanceOutcomeAverageScore;
	PanelState.AlignedTightFollowUpPacketStructureHistoryCount =
		ActiveCoachMemorySnapshot.AlignedTightFollowUpPacketStructureHistoryCount;
	PanelState.AlignedBroadRecommendedPacketStructureHistoryCount =
		ActiveCoachMemorySnapshot.AlignedBroadRecommendedPacketStructureHistoryCount;
	PanelState.AlignedTightFollowUpPacketStructureAverageOutcomeScore =
		ActiveCoachMemorySnapshot.AlignedTightFollowUpPacketStructureAverageOutcomeScore;
	PanelState.AlignedBroadRecommendedPacketStructureAverageOutcomeScore =
		ActiveCoachMemorySnapshot.AlignedBroadRecommendedPacketStructureAverageOutcomeScore;
	PanelState.AlignedTightFollowUpPacketStructureOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AlignedTightFollowUpPacketStructureOutcomeHistoryCount;
	PanelState.AlignedBroadRecommendedPacketStructureOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AlignedBroadRecommendedPacketStructureOutcomeHistoryCount;
	PanelState.AlignedTightFollowUpPacketStructureOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AlignedTightFollowUpPacketStructureOutcomeAverageScore;
	PanelState.AlignedBroadRecommendedPacketStructureOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AlignedBroadRecommendedPacketStructureOutcomeAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketOutcomeHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketOutcomeHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketOutcomeAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketOutcomeAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustOutcomeHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketTrustOutcomeHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustOutcomeAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketTrustOutcomeAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustReliableHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketTrustReliableHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableAverageOutcomeScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustReliableAverageOutcomeScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableAverageOutcomeScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketTrustReliableAverageOutcomeScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeAcceptedHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeAcceptedHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeAcceptedHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeAcceptedHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeAcceptedAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableOutcomeAcceptedAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeAcceptedAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableOutcomeAcceptedAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableLaneOutcomeHistoryCount =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustReliableLaneOutcomeHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableLaneOutcomeHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableLaneOutcomeHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableLaneOutcomeAverageScore =
		ActiveCoachMemorySnapshot.AcceptedAlignedTightFollowUpPacketTrustReliableLaneOutcomeAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableLaneOutcomeAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableLaneOutcomeAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactAcceptedHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactAcceptedHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactAcceptedHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactAcceptedHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactAcceptedAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactAcceptedAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactAcceptedAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactAcceptedAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeAcceptedHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeAcceptedHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeAcceptedHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeAcceptedHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeAcceptedAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeAcceptedAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeAcceptedAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeAcceptedAverageScore;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeReliableHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeReliableHistoryCount;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeReliableHistoryCount =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeReliableHistoryCount;
	PanelState.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeReliableAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedTightFollowUpPacketTrustReliableExactOutcomeReliableAverageScore;
	PanelState.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeReliableAverageScore =
		ActiveCoachMemorySnapshot
			.AcceptedAlignedBroadRecommendedPacketTrustReliableExactOutcomeReliableAverageScore;
	PanelState.bRepositoryVerificationPassed = ActiveRepositoryRoundTripVerification.bDidRoundTripPass;
	PanelState.bRepositoryVerificationNeedsAttention = ActiveRepositoryRoundTripVerification.ResolvedPath.IsEmpty()
		|| !ActiveRepositoryRoundTripVerification.bDidRoundTripPass;
	if (HasActiveRun())
	{
		FHyperTwistTrainingImportedGeneratedModeLaunchRequest LatestGeneratedModeLaunchRequest;
		if (TryGetLatestGeneratedModeLaunchRequestForActiveDeck(LatestGeneratedModeLaunchRequest))
		{
			PanelState.bHasLatestGeneratedModeLaunchRequest = true;
			PanelState.LatestGeneratedModeLaunchRequestId = LatestGeneratedModeLaunchRequest.RequestId;
			PanelState.LatestGeneratedModeLaunchRequestedAtUtc =
				LatestGeneratedModeLaunchRequest.RequestedAtUtc;
			PanelState.LatestGeneratedModeRuntimeModeId =
				LatestGeneratedModeLaunchRequest.LaunchConfig.RuntimeModeId;
			PanelState.LatestGeneratedModeSelectorSummaryLine =
				HyperTwistTrainingSubsystemInternal::FormatGeneratedModeSelectorSummary(
					ActiveRunState.ActiveDeck,
					LatestGeneratedModeLaunchRequest
				);
		}

		FHyperTwistTrainingImportedRuntimeSurface ActiveRuntimeSurface;
		if (UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
				ActiveRunState.ActiveDeck,
				ActiveRuntimeSurface)
			&& ActiveRuntimeSurface.IsStructurallyValid()
			&& ActiveRuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
		{
			PanelState.bHasActiveGeneratedModeExecutionTarget = true;

			FHyperTwistTrainingImportedGeneratedModeLaunchConfig ActiveExecutionLaunchConfig;
			bool bRequiresLaunchRequestRefresh = false;
			FString GeneratedModeExecutionBlockedReason;
			if (HyperTwistTrainingSubsystemInternal::TryResolveGeneratedModeExecutionLaunchConfig(
					ActiveRunState,
					ActiveImportedGeneratedModeLaunchRequest,
					ActiveExecutionLaunchConfig,
					bRequiresLaunchRequestRefresh,
					GeneratedModeExecutionBlockedReason))
			{
				PanelState.bCanExecuteActiveGeneratedModeLaunchRequest = true;
				PanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest =
					bRequiresLaunchRequestRefresh;
			}
			else
			{
				PanelState.ActiveGeneratedModeExecutionBlockedReason =
					GeneratedModeExecutionBlockedReason;
			}
		}
	}

	const FHyperTwistTrainingCoachSessionQueueStateEntry* NextRunnableEntry =
		HyperTwistTrainingSubsystemInternal::FindNextRunnableCoachQueueEntry(ActiveCoachSessionQueueState);
	PanelState.bHasRunnableQueueEntry = NextRunnableEntry != nullptr;
	PanelState.bHasQueueWork = ActiveCoachSessionQueueState.IsStructurallyValid()
		? ActiveCoachSessionQueueState.TotalEntryCount > 0
		: ActiveCoachSessionQueueSummary.TotalEntryCount > 0;
	PanelState.bHasDeferredQueueWork = ActiveCoachSessionQueueState.IsStructurallyValid()
		? ActiveCoachSessionQueueState.DeferredEntryCount > 0
		: false;
	PanelState.TotalQueueEntryCount = ActiveCoachSessionQueueState.IsStructurallyValid()
		? ActiveCoachSessionQueueState.TotalEntryCount
		: ActiveCoachSessionQueueSummary.TotalEntryCount;
	PanelState.ReadyQueueEntryCount = ActiveCoachSessionQueueState.IsStructurallyValid()
		? ActiveCoachSessionQueueState.ReadyEntryCount
		: (ActiveCoachSessionQueueSummary.bHasImmediateQueue ? 1 : 0);
	PanelState.DeferredQueueEntryCount = ActiveCoachSessionQueueState.IsStructurallyValid()
		? ActiveCoachSessionQueueState.DeferredEntryCount
		: 0;
	PanelState.FollowUpQueueEntryCount = ActiveCoachSessionQueueState.IsStructurallyValid()
		? ActiveCoachSessionQueueState.Entries.FilterByPredicate(
			[](const FHyperTwistTrainingCoachSessionQueueStateEntry& Candidate)
			{
				return Candidate.bRequiresFollowUp;
			}
		).Num()
		: ActiveCoachSessionQueueSummary.FollowUpEntryCount;

	const FHyperTwistTrainingDeck RecommendedDeck = BuildActiveCoachRecommendedDeck(3);
	const FHyperTwistTrainingDeck FollowUpDeck = BuildActiveCoachFollowUpDeck(3);
	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget RecommendedBudget =
		HyperTwistTrainingSubsystemInternal::ResolvePreferredCoachCaseBudget(
			3,
			EHyperTwistTrainingCoachGuidanceLane::Recommended,
			ActiveCoachMemorySnapshot,
			false
		);
	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget FollowUpBudget =
		HyperTwistTrainingSubsystemInternal::ResolvePreferredCoachCaseBudget(
			3,
			EHyperTwistTrainingCoachGuidanceLane::FollowUp,
			ActiveCoachMemorySnapshot,
			false
		);
	PanelState.bCanStartCoachRecommendedRun = RecommendedDeck.IsStructurallyValid();
	PanelState.bCanStartCoachFollowUpRun = FollowUpDeck.IsStructurallyValid();
	FHyperTwistTrainingDeck QueueLaunchDeck;
	HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget QueueLaunchBudget;
	if (NextRunnableEntry != nullptr)
	{
		QueueLaunchDeck = HyperTwistTrainingSubsystemInternal::BuildCoachQueueDeckFromEntry(
			*NextRunnableEntry,
			ActiveRunState,
			ActiveCoachMemorySnapshot,
			3
		);
		QueueLaunchBudget = HyperTwistTrainingSubsystemInternal::ResolveQueueLaunchBudgetFromEntry(
			*NextRunnableEntry,
			QueueLaunchDeck,
			ActiveCoachMemorySnapshot,
			3
		);
	}
	PanelState.bCanStartQueuedRun = NextRunnableEntry != nullptr && QueueLaunchDeck.IsStructurallyValid();
	const bool bShouldPresentPostReviewIdleClosure =
		!HasActiveRun()
		&& !RetainedRepositoryViewUserId.IsEmpty()
		&& !ActiveReviewProgramSummary.LastCompletedPlanId.IsEmpty()
		&& ActiveReviewProgramSummary.PendingPlanCount == 0
		&& !ActiveReviewProgramSummary.bHasCarryover
		&& !ActiveReviewPlanState.IsStructurallyValid()
		&& !ActiveCoachSessionQueueSummary.IsStructurallyValid()
		&& !ActiveCoachSessionQueueState.IsStructurallyValid();
	if (bShouldPresentPostReviewIdleClosure)
	{
		PanelState.bHasCoachGuidance = false;
		PanelState.bHasFollowUpGuidance = false;
		PanelState.bHasRunnableQueueEntry = false;
		PanelState.bHasQueueWork = false;
		PanelState.bHasDeferredQueueWork = false;
		PanelState.TotalQueueEntryCount = 0;
		PanelState.ReadyQueueEntryCount = 0;
		PanelState.DeferredQueueEntryCount = 0;
		PanelState.FollowUpQueueEntryCount = 0;
		PanelState.bCanStartQueuedRun = false;
		PanelState.bCanStartCoachFollowUpRun = false;
		PanelState.bCanStartCoachRecommendedRun = false;
		PanelState.NextQueueSourceLabel.Reset();
		PanelState.ActiveQueueEntryId.Reset();
		PanelState.FocusCaseCount = 0;
	}

	const bool bPreferFollowUpGuidance =
		PanelState.bHasFollowUpGuidance
		&& ActiveCoachMemorySnapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp;
	if (NextRunnableEntry != nullptr)
	{
		PanelState.Headline = NextRunnableEntry->Headline;
		const FString ActionLabel = HyperTwistTrainingSubsystemInternal::ResolveQueueActionLabel(
			NextRunnableEntry->SourceLabel
		);
		PanelState.SuggestedLaunchCaseBudget = QueueLaunchDeck.Cases.Num();
		PanelState.LaunchBudgetReasonLine = QueueLaunchBudget.ReasonLine;
		PanelState.SecondaryLine = PanelState.SuggestedLaunchCaseBudget > 0
			? FString::Printf(
				TEXT("%s | %s"),
				*ActionLabel,
				*HyperTwistTrainingSubsystemInternal::FormatLaunchBudgetLabel(
					PanelState.SuggestedLaunchCaseBudget)
			)
			: ActionLabel;
		PanelState.PrimaryActionLabel = ActionLabel;
		PanelState.NextQueueSourceLabel = NextRunnableEntry->SourceLabel;
		PanelState.ActiveQueueEntryId = NextRunnableEntry->EntryId;
		PanelState.FocusDeckId = NextRunnableEntry->FocusDeckId;
		PanelState.FocusMethodSegmentId = NextRunnableEntry->FocusMethodSegmentId;
		PanelState.FocusCaseCount = NextRunnableEntry->FocusCaseIds.Num();
		PanelState.SuggestedMode = NextRunnableEntry->SuggestedMode;
		PanelState.SuggestedSelectionPolicy = NextRunnableEntry->SuggestedSelectionPolicy;
	}
	else if (bPreferFollowUpGuidance)
	{
		PanelState.Headline = ActiveCoachFollowUpBrief.Headline;
		PanelState.SuggestedLaunchCaseBudget = FollowUpDeck.Cases.Num();
		PanelState.LaunchBudgetReasonLine = FollowUpBudget.ReasonLine;
		PanelState.SecondaryLine = PanelState.SuggestedLaunchCaseBudget > 0
			? FString::Printf(
				TEXT("%s | %s"),
				*ActiveCoachFollowUpBrief.PrimaryActionLabel,
				*HyperTwistTrainingSubsystemInternal::FormatLaunchBudgetLabel(
					PanelState.SuggestedLaunchCaseBudget)
			)
			: ActiveCoachFollowUpBrief.PrimaryActionLabel;
		PanelState.PrimaryActionLabel = ActiveCoachFollowUpBrief.PrimaryActionLabel;
		PanelState.FocusDeckId = ActiveCoachFollowUpBrief.FocusDeckId;
		PanelState.FocusMethodSegmentId = ActiveCoachFollowUpBrief.FocusMethodSegmentId;
		PanelState.FocusCaseCount = ActiveCoachFollowUpBrief.FocusCaseIds.Num();
		PanelState.SuggestedMode = ActiveCoachFollowUpBrief.SuggestedMode;
		PanelState.SuggestedSelectionPolicy = ActiveCoachFollowUpBrief.SuggestedSelectionPolicy;
	}
	else if (PanelState.bHasCoachGuidance)
	{
		PanelState.Headline = ActiveCoachBrief.Headline;
		PanelState.SuggestedLaunchCaseBudget = RecommendedDeck.Cases.Num();
		PanelState.LaunchBudgetReasonLine = RecommendedBudget.ReasonLine;
		PanelState.SecondaryLine = PanelState.SuggestedLaunchCaseBudget > 0
			? FString::Printf(
				TEXT("%s | %s"),
				*ActiveCoachBrief.PrimaryActionLabel,
				*HyperTwistTrainingSubsystemInternal::FormatLaunchBudgetLabel(
					PanelState.SuggestedLaunchCaseBudget)
			)
			: ActiveCoachBrief.PrimaryActionLabel;
		PanelState.PrimaryActionLabel = ActiveCoachBrief.PrimaryActionLabel;
		PanelState.FocusDeckId = ActiveCoachBrief.FocusDeckId;
		PanelState.FocusMethodSegmentId = ActiveCoachBrief.FocusMethodSegmentId;
		PanelState.FocusCaseCount = ActiveCoachBrief.FocusCaseIds.Num();
		PanelState.SuggestedMode = ActiveCoachBrief.SuggestedMode;
		PanelState.SuggestedSelectionPolicy = ActiveCoachBrief.SuggestedSelectionPolicy;
	}
	else if (HasActiveRun())
	{
		PanelState.Headline = ActiveRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
			? TEXT("Training run is complete")
			: TEXT("Training run is active");
		PanelState.SecondaryLine = ActiveRunState.ActiveDeck.Title.IsEmpty()
			? TEXT("Refresh coaching state to continue.")
			: ActiveRunState.ActiveDeck.Title;
	}
	else
	{
		PanelState.Headline = TEXT("Training state is stable");
		PanelState.SecondaryLine = TEXT("No immediate coach queue work is active.");
	}

	if (PanelState.PreferredLaunchBudgetSourceLabel
		== TEXT("recommendation-history-deferred-tightened-launch")
		&& PanelState.SuggestedLaunchCaseBudget > 0)
	{
		const FString DeferredOverflowNote = FString::Printf(
			TEXT("deferred overflow memory active (%d launches / %d deferred cases)"),
			PanelState.DeferredTightenedLaunchHistoryCount,
			PanelState.DeferredLaunchHistoryCaseCount
		);
		PanelState.SecondaryLine = PanelState.SecondaryLine.IsEmpty()
			? DeferredOverflowNote
			: FString::Printf(TEXT("%s | %s"), *PanelState.SecondaryLine, *DeferredOverflowNote);
	}

	PanelState.QueueSuppressionLine =
		HyperTwistTrainingSubsystemInternal::ResolveQueueSuppressionLine(ActiveCoachSessionQueueSummary);
	const FString BaseQueueStatusLine = PanelState.TotalQueueEntryCount > 0
		? FString::Printf(
			TEXT("Queue: %d total, %d ready, %d deferred"),
			PanelState.TotalQueueEntryCount,
			PanelState.ReadyQueueEntryCount,
			PanelState.DeferredQueueEntryCount
		)
		: TEXT("Queue: no queued coach work");
	PanelState.QueueStatusLine = PanelState.QueueSuppressionLine.IsEmpty()
		? BaseQueueStatusLine
		: FString::Printf(
			TEXT("%s | %s"),
			*BaseQueueStatusLine,
			*PanelState.QueueSuppressionLine
		);
	const FString RecognitionProviderLabel = ActiveRecognitionSessionState.ServiceHealth.ProviderLabel.IsEmpty()
		? (ActiveRecognitionSessionState.bUsingProviderBackedClient ? TEXT("local-http-sidecar") : TEXT("mock"))
		: ActiveRecognitionSessionState.ServiceHealth.ProviderLabel;
	const FString RecognitionTransportState = ActiveRecognitionSessionState.ServiceHealth.bReady
		? TEXT("ready")
		: (ActiveRecognitionSessionState.ServiceHealth.LastError.IsEmpty()
			? TEXT("not-ready")
			: *ActiveRecognitionSessionState.ServiceHealth.LastError);
	PanelState.RecognitionStatusLine = FString::Printf(
		TEXT("Recognition: %s | Service: %s | Session: %s | Frames %d | Commits %d | Corrections %d | Finalizations %d"),
		*RecognitionProviderLabel,
		*RecognitionTransportState,
		ActiveRecognitionSessionState.bSessionOpen ? TEXT("open") : TEXT("closed"),
		ActiveRecognitionSessionState.SubmittedFrameCount,
		ActiveRecognitionSessionState.CommittedObservationCount,
		ActiveRecognitionSessionState.CorrectionEventCount,
		ActiveRecognitionSessionState.FinalizedSessionCount
	);
	const bool bCoachPrefersRecognitionReview =
		ActiveCoachBrief.bPreferRecognitionReplayReview || ActiveCoachFollowUpBrief.bPreferRecognitionReplayReview;
	const int32 ReplayCorrectionCount = HyperTwistTrainingSubsystemInternal::CountRecognitionCorrectionEvents(
		ActiveRunState.ReplayPacket.Events
	);
	PanelState.RecognitionDetailLine = FString::Printf(
		TEXT("Replay episodes %d | Ambiguous %d | Replay corrections %d | Avg commit confidence %s | Coach recognition review %s"),
		ActiveRecognitionReplaySummary.EpisodeCount,
		ActiveRecognitionReplaySummary.AmbiguousEpisodeCount,
		ReplayCorrectionCount,
		*HyperTwistTrainingSubsystemInternal::FormatRecognitionConfidence(
			ActiveRecognitionReplaySummary.AverageCommitConfidence
		),
		bCoachPrefersRecognitionReview ? TEXT("preferred") : TEXT("inactive")
	);
	const bool bHasActiveReviewPlan = ActiveReviewPlanState.IsStructurallyValid();
	const bool bHasReviewPolicyPreview =
		HasActiveRun()
		&& ActiveRunState.Session.SessionState != EHyperTwistTrainingSessionState::Completed
		&& ActiveRunState.Session.SessionState != EHyperTwistTrainingSessionState::Aborted;
	FHyperTwistTrainingReviewPolicy DisplayedReviewPolicy;
	if (bHasActiveReviewPlan)
	{
		DisplayedReviewPolicy = ActiveReviewPlanState.Policy;
	}
	else if (bHasReviewPolicyPreview)
	{
		DisplayedReviewPolicy = HyperTwistTrainingSubsystemInternal::ResolveActiveReviewPolicy(
			ActiveRunState,
			ActiveCoachActionPlan,
			ActiveRunState.Session.Mode
		);
	}
	const bool bHasDisplayedReviewPolicy = bHasActiveReviewPlan || bHasReviewPolicyPreview;
	const bool bPolicyFromActiveCoachActionPlan =
		!bHasActiveReviewPlan
		&& bHasReviewPolicyPreview
		&& HyperTwistTrainingSubsystemInternal::ShouldPreferRecognitionReplayReviewForActiveRun(
			ActiveRunState,
			ActiveCoachActionPlan
		);
	const FString ReviewPolicySourceLabel = bHasActiveReviewPlan
		? TEXT("active-review-plan")
		: (bPolicyFromActiveCoachActionPlan
			? TEXT("active-coach-action-plan")
			: (bHasReviewPolicyPreview ? TEXT("delivery-mode-default") : TEXT("idle")));
	const FString ReviewPolicyLabel = bHasDisplayedReviewPolicy
		? (DisplayedReviewPolicy.PolicyLabel.IsEmpty()
			? HyperTwistTrainingSubsystemInternal::EnumDisplayName(DisplayedReviewPolicy.PolicyKind)
			: DisplayedReviewPolicy.PolicyLabel)
		: TEXT("none");
	PanelState.ReviewPolicyStatusLine = !bHasDisplayedReviewPolicy
		? TEXT("Review: no active review policy is materialized")
		: FString::Printf(
			TEXT("Review: %s | Policy: %s | Mode: %s | Recognition review: %s"),
			bHasActiveReviewPlan ? TEXT("active plan") : TEXT("preview"),
			*ReviewPolicyLabel,
			*HyperTwistTrainingSubsystemInternal::EnumDisplayName(DisplayedReviewPolicy.DeliveryMode),
			DisplayedReviewPolicy.bPreferRecognitionReplayReview ? TEXT("preferred") : TEXT("inactive")
		);
	PanelState.ReviewPolicyDetailLine = !bHasDisplayedReviewPolicy
		? TEXT("Review detail: start or inspect a run to materialize review-policy state.")
		: (bHasActiveReviewPlan
			? FString::Printf(
				TEXT("Plan: %s | Source deck: %s | Entries: %d | Pending %d | Repeat %d | Completed %d | Needs coach: %s | Source: %s"),
				ActiveReviewPlanState.PlanId.IsEmpty() ? TEXT("n/a") : *ActiveReviewPlanState.PlanId,
				ActiveReviewPlanState.SourceDeckId.IsEmpty() ? TEXT("n/a") : *ActiveReviewPlanState.SourceDeckId,
				ActiveReviewPlanState.Entries.Num(),
				ActiveReviewFlowStatus.PendingCount,
				ActiveReviewFlowStatus.RepeatCount,
				ActiveReviewFlowStatus.CompletedCount,
				ActiveReviewFlowStatus.bNeedsCoachIntervention ? TEXT("yes") : TEXT("no"),
				*ReviewPolicySourceLabel
			)
			: FString::Printf(
				TEXT("Preview source: %s | Kind: %s | Max cases: %d | Due bias %.0f | Recognition bias %.0f | Short sets: %s"),
				*ReviewPolicySourceLabel,
				*HyperTwistTrainingSubsystemInternal::EnumDisplayName(DisplayedReviewPolicy.PolicyKind),
				DisplayedReviewPolicy.MaxCases,
				DisplayedReviewPolicy.DueCaseBias,
				DisplayedReviewPolicy.RecognitionBias,
				DisplayedReviewPolicy.bPreferShortReviewSets ? TEXT("yes") : TEXT("no")
			));
	PanelState.VerificationStatusLine = ActiveRepositoryRoundTripVerification.ResolvedPath.IsEmpty()
		? TEXT("Verification: not run yet")
		: (ActiveRepositoryRoundTripVerification.bDidRoundTripPass
			? TEXT("Verification: repository round-trip passed")
			: TEXT("Verification: repository round-trip needs attention"));
	return PanelState;
}

FHyperTwistTrainingDeckHistorySummary UHyperTwistTrainingSubsystem::GetActiveDeckHistorySummary() const
{
	return ActiveDeckHistorySummary;
}

FHyperTwistTrainingTimingTrendSummary UHyperTwistTrainingSubsystem::GetActiveTimingTrendSummary() const
{
	return ActiveTimingTrendSummary;
}

FHyperTwistTrainingPersonalBestSummary UHyperTwistTrainingSubsystem::GetActivePersonalBestSummary() const
{
	return ActivePersonalBestSummary;
}

FHyperTwistTrainingDeckScopedStats UHyperTwistTrainingSubsystem::GetActiveDeckScopedStats() const
{
	return ActiveDeckScopedStats;
}

FHyperTwistTrainingCaseScopedStats UHyperTwistTrainingSubsystem::GetActiveCurrentCaseScopedStats() const
{
	return ActiveCurrentCaseScopedStats;
}

FHyperTwistTrainingLearnerDeckStateSummary UHyperTwistTrainingSubsystem::GetActiveLearnerDeckStateSummary() const
{
	return ActiveLearnerDeckStateSummary;
}

FHyperTwistTrainingLearnerProfile UHyperTwistTrainingSubsystem::GetActiveLearnerProfile() const
{
	return ActiveLearnerProfile;
}

FHyperTwistTrainingCoachMemorySnapshot UHyperTwistTrainingSubsystem::GetActiveCoachMemorySnapshot() const
{
	return ActiveCoachMemorySnapshot;
}

FHyperTwistReplayReviewAnalytics UHyperTwistTrainingSubsystem::GetActiveReplayReviewAnalytics() const
{
	return ActiveReplayReviewAnalytics;
}

FHyperTwistRecognitionReplaySummary UHyperTwistTrainingSubsystem::GetActiveRecognitionReplaySummary() const
{
	return ActiveRecognitionReplaySummary;
}

FHyperTwistTrainingRecognitionSessionState UHyperTwistTrainingSubsystem::GetActiveRecognitionSessionState() const
{
	return ActiveRecognitionSessionState;
}

TArray<FHyperTwistCoachSignal> UHyperTwistTrainingSubsystem::GetActiveCoachSignals() const
{
	return ActiveCoachSignals;
}

FHyperTwistCoachBrief UHyperTwistTrainingSubsystem::GetActiveCoachBrief() const
{
	return ActiveCoachBrief;
}

FHyperTwistTrainingCoachActionPlan UHyperTwistTrainingSubsystem::GetActiveCoachActionPlan() const
{
	return ActiveCoachActionPlan;
}

FHyperTwistTrainingCoachActionPlanSummary UHyperTwistTrainingSubsystem::GetActiveCoachActionPlanSummary() const
{
	return ActiveCoachActionPlanSummary;
}

FHyperTwistTrainingCoachActionPlanOutcomeSummary UHyperTwistTrainingSubsystem::GetActiveCoachActionPlanOutcomeSummary() const
{
	return ActiveCoachActionPlanOutcomeSummary;
}

FHyperTwistTrainingCoachActionSequenceSummary UHyperTwistTrainingSubsystem::GetActiveCoachActionSequenceSummary() const
{
	return ActiveCoachActionSequenceSummary;
}

FHyperTwistTrainingCoachActionClosureSummary UHyperTwistTrainingSubsystem::GetActiveCoachActionClosureSummary() const
{
	return ActiveCoachActionClosureSummary;
}

FHyperTwistTrainingCoachClosureMemorySummary UHyperTwistTrainingSubsystem::GetActiveCoachClosureMemorySummary() const
{
	return ActiveCoachClosureMemorySummary;
}

FHyperTwistTrainingCoachRecommendationHistorySummary UHyperTwistTrainingSubsystem::GetActiveCoachRecommendationHistorySummary() const
{
	return ActiveCoachRecommendationHistorySummary;
}

FHyperTwistTrainingCoachCarryForwardPolicySummary UHyperTwistTrainingSubsystem::GetActiveCoachCarryForwardPolicySummary() const
{
	return ActiveCoachCarryForwardPolicySummary;
}

FHyperTwistTrainingCoachArchivePolicySummary UHyperTwistTrainingSubsystem::GetActiveCoachArchivePolicySummary() const
{
	return ActiveCoachArchivePolicySummary;
}

FHyperTwistCoachBrief UHyperTwistTrainingSubsystem::GetActiveCoachFollowUpBrief() const
{
	return ActiveCoachFollowUpBrief;
}

FHyperTwistCoachSessionQueueSummary UHyperTwistTrainingSubsystem::GetActiveCoachSessionQueueSummary() const
{
	return ActiveCoachSessionQueueSummary;
}

FHyperTwistTrainingCoachSessionQueueState UHyperTwistTrainingSubsystem::GetActiveCoachSessionQueueState() const
{
	return ActiveCoachSessionQueueState;
}

FHyperTwistCoachScheduleHorizonSummary UHyperTwistTrainingSubsystem::GetActiveCoachScheduleHorizonSummary() const
{
	return ActiveCoachScheduleHorizonSummary;
}

FHyperTwistCoachSchedulePolicySummary UHyperTwistTrainingSubsystem::GetActiveCoachSchedulePolicySummary() const
{
	return ActiveCoachSchedulePolicySummary;
}

FHyperTwistTrainingCoachSessionQueueExecutionSummary UHyperTwistTrainingSubsystem::GetActiveCoachSessionQueueExecutionSummary() const
{
	return ActiveCoachSessionQueueExecutionSummary;
}

TArray<FHyperTwistTrainingMethodSegment> UHyperTwistTrainingSubsystem::GetActiveLearnerMethodSegments() const
{
	return ActiveLearnerMethodSegments;
}

TArray<FHyperTwistTrainingLearnerPreset> UHyperTwistTrainingSubsystem::GetActiveLearnerPresets() const
{
	return ActiveLearnerPresets;
}

TArray<FHyperTwistTrainingSessionTemplate> UHyperTwistTrainingSubsystem::GetActiveTrainingSessionTemplates() const
{
	return ActiveTrainingSessionTemplates;
}

TArray<FHyperTwistTrainingSessionTemplate> UHyperTwistTrainingSubsystem::GetTrainingSessionTemplatesForUser(
	const FString& UserId,
	const FString& ReferenceUtc
) const
{
	return BuildTrainingSessionTemplatesForUser(UserId, ReferenceUtc);
}

TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> UHyperTwistTrainingSubsystem::GetMethodDrillFavoritesForUser(
	const FString& UserId,
	const FString& MethodSegmentId
) const
{
	return UHyperTwistTrainingRepositoryLibrary::ListMethodDrillFavorites(
		TrainingRepositoryState,
		UserId,
		MethodSegmentId
	);
}

TArray<FHyperTwistTrainingMethodDrillBatch> UHyperTwistTrainingSubsystem::GetMethodDrillBatchesForUser(
	const FString& UserId,
	const FString& MethodSegmentId
) const
{
	return UHyperTwistTrainingRepositoryLibrary::ListMethodDrillBatches(
		TrainingRepositoryState,
		UserId,
		MethodSegmentId
	);
}

TArray<FHyperTwistTrainingMethodDrillBatch> UHyperTwistTrainingSubsystem::GetResumableMethodDrillBatchesForUser(
	const FString& UserId,
	const FString& MethodSegmentId
) const
{
	return UHyperTwistTrainingRepositoryLibrary::ListResumableDrillBatches(
		TrainingRepositoryState,
		UserId,
		MethodSegmentId
	);
}

FHyperTwistTrainingMethodDrillBatchReadiness UHyperTwistTrainingSubsystem::DeriveMethodDrillBatchReadiness(
	const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
	const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition
) const
{
	return UHyperTwistTrainingRepositoryLibrary::DeriveDrillBatchReadiness(
		DrillBatch,
		DrillDefinition
	);
}

FHyperTwistTrainingMethodDrillBatch UHyperTwistTrainingSubsystem::RebuildMethodDrillBatchForResume(
	const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
	const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition
) const
{
	return UHyperTwistTrainingRepositoryLibrary::RebuildDrillBatchForResume(
		DrillBatch,
		DrillDefinition
	);
}

FHyperTwistTrainingMethodDrillDefinition UHyperTwistTrainingSubsystem::BuildFavoriteFirstMethodDrillDefinition(
	const FHyperTwistTrainingMethodDrillDefinition& BaseDefinition,
	const FString& UserId,
	int32 MaxFavoriteCases
) const
{
	if (!BaseDefinition.IsStructurallyValid())
	{
		return BaseDefinition;
	}

	const FString EffectiveUserId = !UserId.IsEmpty() ? UserId : ActiveMethodDrillRunState.UserId;
	if (EffectiveUserId.IsEmpty())
	{
		return BaseDefinition;
	}

	const TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> Favorites =
		UHyperTwistTrainingRepositoryLibrary::ListMethodDrillFavorites(
			TrainingRepositoryState,
			EffectiveUserId,
			BaseDefinition.MethodDescriptor.SegmentId
		);
	return UHyperTwistTrainingRepositoryLibrary::BuildDrillDefinitionFavoriteFirst(
		BaseDefinition,
		Favorites,
		MaxFavoriteCases
	);
}

TArray<FHyperTwistTrainingCaseRecommendation> UHyperTwistTrainingSubsystem::GetActiveCaseRecommendations() const
{
	return ActiveCaseRecommendations;
}

FHyperTwistTrainingReviewPlanState UHyperTwistTrainingSubsystem::GetActiveReviewPlanState() const
{
	return ActiveReviewPlanState;
}

FHyperTwistTrainingReviewFlowStatus UHyperTwistTrainingSubsystem::GetActiveReviewFlowStatus() const
{
	return ActiveReviewFlowStatus;
}

FHyperTwistTrainingReviewProgramSummary UHyperTwistTrainingSubsystem::GetActiveReviewProgramSummary() const
{
	return ActiveReviewProgramSummary;
}

FHyperTwistTrainingTimerExportPacket UHyperTwistTrainingSubsystem::BuildTrainingTimerExportPacket(
	const FString& UserId,
	const FString& DeckId,
	const FString& ReferenceUtc
) const
{
	return UHyperTwistTrainingRepositoryLibrary::NormalizeTimerExportPacket(
		UHyperTwistTrainingRepositoryLibrary::ExportTimerResultsForDeck(
			TrainingRepositoryState,
			UserId,
			DeckId,
			ReferenceUtc
		)
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredRunRecord(
	const FString& TrainingSessionId,
	FHyperTwistTrainingRunRecord& OutRunRecord
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetRunRecord(
		TrainingRepositoryState,
		TrainingSessionId,
		OutRunRecord
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredLearnerState(
	const FString& UserId,
	const FString& DeckId,
	const FString& CaseId,
	FHyperTwistTrainingCaseLearnerState& OutLearnerState
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetLearnerState(
		TrainingRepositoryState,
		UserId,
		DeckId,
		CaseId,
		OutLearnerState
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredReviewPlan(
	const FString& PlanId,
	FHyperTwistTrainingReviewPlanState& OutReviewPlan
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetReviewPlan(
		TrainingRepositoryState,
		PlanId,
		OutReviewPlan
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredCoachActionPlan(
	const FString& PlanId,
	FHyperTwistTrainingCoachActionPlan& OutActionPlan
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetCoachActionPlan(
		TrainingRepositoryState,
		PlanId,
		OutActionPlan
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredCoachSessionQueueState(
	const FString& UserId,
	const FString& QueueId,
	FHyperTwistTrainingCoachSessionQueueState& OutQueueState
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetCoachSessionQueueState(
		TrainingRepositoryState,
		UserId,
		QueueId,
		OutQueueState
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredTrainingSessionTemplate(
	const FString& UserId,
	const FString& TemplateId,
	FHyperTwistTrainingSessionTemplate& OutTemplate
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetStoredTrainingSessionTemplate(
		TrainingRepositoryState,
		UserId,
		TemplateId,
		OutTemplate
	);
}

bool UHyperTwistTrainingSubsystem::SaveTrainingSessionTemplate(
	const FHyperTwistTrainingSessionTemplate& SessionTemplate
)
{
	if (!SessionTemplate.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertStoredTrainingSessionTemplate(
		TrainingRepositoryState,
		SessionTemplate
	);
	RefreshRepositoryViews();

	return true;
}

bool UHyperTwistTrainingSubsystem::SaveMethodDrillFavorite(
	const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
)
{
	if (!FavoriteEntry.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillFavorite(
		TrainingRepositoryState,
		FavoriteEntry
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::RemoveMethodDrillFavorite(
	const FString& UserId,
	const FString& DrillId,
	const FString& CaseId
)
{
	if (UserId.IsEmpty() || DrillId.IsEmpty() || CaseId.IsEmpty())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveMethodDrillFavorite(
		TrainingRepositoryState,
		UserId,
		DrillId,
		CaseId
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::TryGetStoredMethodDrillBatch(
	const FString& UserId,
	const FString& BatchId,
	FHyperTwistTrainingMethodDrillBatch& OutBatch
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetMethodDrillBatch(
		TrainingRepositoryState,
		UserId,
		BatchId,
		OutBatch
	);
}

bool UHyperTwistTrainingSubsystem::SaveMethodDrillBatch(
	const FHyperTwistTrainingMethodDrillBatch& DrillBatch
)
{
	if (!DrillBatch.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillBatch(
		TrainingRepositoryState,
		DrillBatch
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::SaveCoachSessionQueueState(
	const FHyperTwistTrainingCoachSessionQueueState& QueueState
)
{
	if (!QueueState.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
		TrainingRepositoryState,
		QueueState
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::DeferCoachSessionQueueEntry(
	const FString& EntryId,
	const FString& DeferredUntilUtc,
	const FString& DeferralReasonLabel,
	bool bManualReschedule
)
{
	if (!ActiveCoachSessionQueueState.IsStructurallyValid() || EntryId.IsEmpty() || DeferredUntilUtc.IsEmpty())
	{
		return false;
	}

	ActiveCoachSessionQueueState = UHyperTwistTrainingRepositoryLibrary::DeferCoachSessionQueueEntry(
		ActiveCoachSessionQueueState,
		EntryId,
		DeferredUntilUtc,
		DeferralReasonLabel,
		bManualReschedule,
		FDateTime::UtcNow().ToIso8601()
	);
	if (!ActiveCoachSessionQueueState.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
		TrainingRepositoryState,
		ActiveCoachSessionQueueState
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::PromoteCoachSessionQueueEntry(
	const FString& EntryId,
	const FString& StartActionSourceLabel
)
{
	if (!ActiveCoachSessionQueueState.IsStructurallyValid() || EntryId.IsEmpty())
	{
		return false;
	}

	ActiveCoachSessionQueueState = UHyperTwistTrainingRepositoryLibrary::PromoteCoachSessionQueueEntry(
		ActiveCoachSessionQueueState,
		EntryId,
		StartActionSourceLabel,
		FDateTime::UtcNow().ToIso8601()
	);
	if (!ActiveCoachSessionQueueState.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
		TrainingRepositoryState,
		ActiveCoachSessionQueueState
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::RemoveMethodDrillBatch(
	const FString& UserId,
	const FString& BatchId
)
{
	if (UserId.IsEmpty() || BatchId.IsEmpty())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveMethodDrillBatch(
		TrainingRepositoryState,
		UserId,
		BatchId
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::RemoveTrainingSessionTemplate(
	const FString& UserId,
	const FString& TemplateId
)
{
	if (UserId.IsEmpty() || TemplateId.IsEmpty())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveStoredTrainingSessionTemplate(
		TrainingRepositoryState,
		UserId,
		TemplateId
	);
	RefreshRepositoryViews();

	return true;
}

bool UHyperTwistTrainingSubsystem::SaveTrainingRepositoryStateToDefaultPath(FString& OutResolvedPath) const
{
	return UHyperTwistTrainingPersistenceLibrary::SaveTrainingRepositoryStateToFile(
		TrainingRepositoryState,
		FString(),
		OutResolvedPath
	);
}

bool UHyperTwistTrainingSubsystem::LoadTrainingRepositoryStateFromDefaultPath(FString& OutResolvedPath)
{
	FHyperTwistTrainingRepositoryState LoadedState;
	if (!UHyperTwistTrainingPersistenceLibrary::LoadTrainingRepositoryStateFromFile(FString(), LoadedState, OutResolvedPath))
	{
		return false;
	}

	TrainingRepositoryState = LoadedState;
	RefreshRepositoryViews();
	return true;
}

FHyperTwistTrainingRepositoryRoundTripVerification
UHyperTwistTrainingSubsystem::VerifyTrainingRepositoryRoundTripAtDefaultPath()
{
	ActiveRepositoryRoundTripVerification =
		UHyperTwistTrainingPersistenceLibrary::VerifyTrainingRepositoryStateRoundTrip(
			TrainingRepositoryState,
			FString()
		);
	return ActiveRepositoryRoundTripVerification;
}

bool UHyperTwistTrainingSubsystem::SaveTrainingTimerExportPacketToDefaultPath(
	const FString& UserId,
	const FString& DeckId,
	FString& OutResolvedPath
) const
{
	const FHyperTwistTrainingTimerExportPacket TimerExportPacket = BuildTrainingTimerExportPacket(UserId, DeckId, FString());
	return TimerExportPacket.IsStructurallyValid()
		&& UHyperTwistTrainingPersistenceLibrary::SaveTrainingTimerExportPacketToFile(
			TimerExportPacket,
			FString(),
			OutResolvedPath
		);
}

bool UHyperTwistTrainingSubsystem::ImportTrainingTimerExportPacket(const FHyperTwistTrainingTimerExportPacket& TimerExportPacket)
{
	const FHyperTwistTrainingTimerExportPacket NormalizedPacket =
		UHyperTwistTrainingRepositoryLibrary::NormalizeTimerExportPacket(TimerExportPacket);
	if (!NormalizedPacket.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::ImportTimerResults(
		TrainingRepositoryState,
		NormalizedPacket
	);
	RefreshRepositoryViews();

	return true;
}

bool UHyperTwistTrainingSubsystem::LoadTrainingTimerExportPacketFromFile(
	const FString& UserId,
	const FString& DeckId,
	const FString& ExportPath,
	FString& OutResolvedPath
)
{
	FHyperTwistTrainingTimerExportPacket TimerExportPacket;
	if (!UHyperTwistTrainingPersistenceLibrary::LoadTrainingTimerExportPacketFromFile(
		UserId,
		DeckId,
		ExportPath,
		TimerExportPacket,
		OutResolvedPath
	))
	{
		return false;
	}

	return ImportTrainingTimerExportPacket(TimerExportPacket);
}

bool UHyperTwistTrainingSubsystem::TryMaterializeActiveTrainingSessionTemplate(
	const FString& TemplateId,
	FHyperTwistTrainingDeck& OutDeck
) const
{
	return TryMaterializeTrainingSessionTemplateForUser(
		ActiveRunState.Session.UserId,
		TemplateId,
		FString(),
		OutDeck
	);
}

bool UHyperTwistTrainingSubsystem::TryMaterializeTrainingSessionTemplateForUser(
	const FString& UserId,
	const FString& TemplateId,
	const FString& ReferenceUtc,
	FHyperTwistTrainingDeck& OutDeck
) const
{
	OutDeck = FHyperTwistTrainingDeck();
	if (UserId.IsEmpty() || TemplateId.IsEmpty())
	{
		return false;
	}

	const TArray<FHyperTwistTrainingSessionTemplate> EffectiveTemplates = BuildTrainingSessionTemplatesForUser(
		UserId,
		ReferenceUtc
	);
	const FHyperTwistTrainingSessionTemplate* MatchingTemplate = EffectiveTemplates.FindByPredicate(
		[&TemplateId](const FHyperTwistTrainingSessionTemplate& Candidate)
		{
			return Candidate.TemplateId == TemplateId;
		}
	);
	if (MatchingTemplate == nullptr)
	{
		return false;
	}

	OutDeck = UHyperTwistTrainingCatalogLibrary::MaterializeTrainingSessionTemplateDeck(
		*MatchingTemplate,
		UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog()
	);
	return OutDeck.IsStructurallyValid();
}

FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveReviewDeck(int32 MaxCases) const
{
	FHyperTwistTrainingDeck SourceDeck;
	if (HasActiveRun())
	{
		SourceDeck = ResolveRepositoryFocusDeck();
	}
	else if (ActiveReviewPlanState.IsStructurallyValid())
	{
		if (!ActiveReviewPlanState.SourceDeckId.IsEmpty())
		{
			UHyperTwistTrainingCatalogLibrary::TryFindDeckInCatalog(
				UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog(),
				ActiveReviewPlanState.SourceDeckId,
				SourceDeck
			);
		}
		if (!SourceDeck.IsStructurallyValid())
		{
			SourceDeck = ResolveRepositoryFocusDeck();
		}
	}
	else
	{
		return FHyperTwistTrainingDeck();
	}

	if (!SourceDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingDeck();
	}

	if (!HasActiveRun() && ActiveReviewPlanState.IsStructurallyValid())
	{
		return HyperTwistTrainingSubsystemInternal::BuildReviewDeckFromPlan(
			SourceDeck,
			ActiveReviewPlanState,
			MaxCases
		);
	}

	const FHyperTwistTrainingReviewPolicy ReviewPolicy =
		HyperTwistTrainingSubsystemInternal::ResolveActiveReviewPolicy(
			ActiveRunState,
			ActiveCoachActionPlan,
			ActiveRunState.Session.Mode
		);
	const TArray<FHyperTwistTrainingCaseRecommendation> FilteredRecommendations =
		UHyperTwistTrainingRepositoryLibrary::ApplyReviewPolicyToRecommendations(
			ActiveCaseRecommendations,
			ReviewPolicy,
			MaxCases
		);

	return UHyperTwistTrainingRepositoryLibrary::BuildReviewDeckFromRecommendations(
		SourceDeck,
		FilteredRecommendations,
		MaxCases
	);
}

FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachRecommendedDeck(int32 MaxCases) const
{
	const FHyperTwistTrainingDeck SourceDeck = ResolveRepositoryFocusDeck();
	if (!SourceDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingDeck();
	}

	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget ResolvedBudget =
		HyperTwistTrainingSubsystemInternal::ResolvePreferredCoachCaseBudget(
		MaxCases,
		EHyperTwistTrainingCoachGuidanceLane::Recommended,
		ActiveCoachMemorySnapshot,
		false
	);
	TArray<FHyperTwistTrainingCase> FocusCases;
	for (const FString& FocusCaseId : ActiveCoachBrief.FocusCaseIds)
	{
		const FHyperTwistTrainingCase* MatchingCase = SourceDeck.Cases.FindByPredicate(
			[&FocusCaseId](const FHyperTwistTrainingCase& Candidate)
			{
				return Candidate.CaseId == FocusCaseId;
			}
		);
		if (MatchingCase != nullptr)
		{
			FocusCases.Add(*MatchingCase);
			if (FocusCases.Num() >= ResolvedBudget.ResolvedCaseCount)
			{
				break;
			}
		}
	}

	if (FocusCases.Num() == 0)
	{
		if (HasActiveRun())
		{
			const FHyperTwistTrainingDeck ReviewDeck = BuildActiveReviewDeck(ResolvedBudget.ResolvedCaseCount);
			if (ReviewDeck.IsStructurallyValid())
			{
				return ReviewDeck;
			}
		}

		for (const FHyperTwistTrainingCase& Candidate : SourceDeck.Cases)
		{
			FocusCases.Add(Candidate);
			if (FocusCases.Num() >= ResolvedBudget.ResolvedCaseCount)
			{
				break;
			}
		}
	}

	if (FocusCases.Num() == 0)
	{
		return FHyperTwistTrainingDeck();
	}

	FHyperTwistTrainingDeck FocusDeck = SourceDeck;
	FocusDeck.Cases = FocusCases;
	FocusDeck.SelectionPolicy = ActiveCoachBrief.SuggestedSelectionPolicy;
	if (ActiveCoachBrief.SuggestedMode != EHyperTwistTrainingDeliveryMode::Timer
		&& !FocusDeck.DeliveryModes.Contains(ActiveCoachBrief.SuggestedMode))
	{
		FocusDeck.DeliveryModes.Insert(ActiveCoachBrief.SuggestedMode, 0);
	}
	if (!ActiveCoachBrief.Headline.IsEmpty())
	{
		FocusDeck.Title = FString::Printf(TEXT("%s Focus"), *ActiveCoachBrief.Headline);
	}
	if (!FocusDeck.Tags.Contains(TEXT("coach-focus")))
	{
		FocusDeck.Tags.Add(TEXT("coach-focus"));
	}
	if (!ActiveCoachBrief.FocusMethodSegmentId.IsEmpty() && FocusDeck.SubsetId.IsEmpty())
	{
		FocusDeck.SubsetId = ActiveCoachBrief.FocusMethodSegmentId;
	}

	return FocusDeck;
}

FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachFollowUpDeck(int32 MaxCases) const
{
	const FHyperTwistTrainingDeck SourceDeck = ResolveRepositoryFocusDeck();
	if (!SourceDeck.IsStructurallyValid() || ActiveCoachFollowUpBrief.UserId.IsEmpty())
	{
		return FHyperTwistTrainingDeck();
	}

	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget ResolvedBudget =
		HyperTwistTrainingSubsystemInternal::ResolvePreferredCoachCaseBudget(
		MaxCases,
		EHyperTwistTrainingCoachGuidanceLane::FollowUp,
		ActiveCoachMemorySnapshot,
		false
	);
	TArray<FHyperTwistTrainingCase> FocusCases;
	for (const FString& FocusCaseId : ActiveCoachFollowUpBrief.FocusCaseIds)
	{
		const FHyperTwistTrainingCase* MatchingCase = SourceDeck.Cases.FindByPredicate(
			[&FocusCaseId](const FHyperTwistTrainingCase& Candidate)
			{
				return Candidate.CaseId == FocusCaseId;
			}
		);
		if (MatchingCase != nullptr)
		{
			FocusCases.Add(*MatchingCase);
			if (FocusCases.Num() >= ResolvedBudget.ResolvedCaseCount)
			{
				break;
			}
		}
	}

	if (FocusCases.Num() == 0)
	{
		return BuildActiveCoachRecommendedDeck(ResolvedBudget.ResolvedCaseCount);
	}

	FHyperTwistTrainingDeck FocusDeck = SourceDeck;
	FocusDeck.Cases = FocusCases;
	FocusDeck.SelectionPolicy = ActiveCoachFollowUpBrief.SuggestedSelectionPolicy;
	if (ActiveCoachFollowUpBrief.SuggestedMode != EHyperTwistTrainingDeliveryMode::Timer
		&& !FocusDeck.DeliveryModes.Contains(ActiveCoachFollowUpBrief.SuggestedMode))
	{
		FocusDeck.DeliveryModes.Insert(ActiveCoachFollowUpBrief.SuggestedMode, 0);
	}
	if (!ActiveCoachFollowUpBrief.Headline.IsEmpty())
	{
		FocusDeck.Title = FString::Printf(TEXT("%s Follow-Up"), *ActiveCoachFollowUpBrief.Headline);
	}
	if (!FocusDeck.Tags.Contains(TEXT("coach-follow-up")))
	{
		FocusDeck.Tags.Add(TEXT("coach-follow-up"));
	}
	if (!ActiveCoachFollowUpBrief.FocusMethodSegmentId.IsEmpty())
	{
		FocusDeck.SubsetId = ActiveCoachFollowUpBrief.FocusMethodSegmentId;
	}

	return FocusDeck;
}

FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveMethodDrillFollowUpDeck() const
{
	if (!ActiveMethodDrillFollowUpTemplate.IsStructurallyValid())
	{
		return FHyperTwistTrainingDeck();
	}

	const FHyperTwistTrainingDeck MaterializedDeck =
		UHyperTwistTrainingCatalogLibrary::MaterializeTrainingSessionTemplateDeck(
			ActiveMethodDrillFollowUpTemplate,
			UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog()
		);
	return MaterializedDeck.IsStructurallyValid() ? MaterializedDeck : FHyperTwistTrainingDeck();
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromTemplate(
	const FString& TemplateId,
	const FString& UserId,
	const FString& SessionId
)
{
	const FString ResolvedUserId = !UserId.IsEmpty()
		? UserId
		: ActiveRunState.Session.UserId;

	FHyperTwistTrainingDeck MaterializedDeck;
	if (!TryMaterializeTrainingSessionTemplateForUser(ResolvedUserId, TemplateId, FString(), MaterializedDeck))
	{
		return FHyperTwistTrainingRunState();
	}

	const TArray<FHyperTwistTrainingSessionTemplate> EffectiveTemplates = BuildTrainingSessionTemplatesForUser(
		ResolvedUserId,
		FString()
	);
	const FHyperTwistTrainingSessionTemplate* MatchingTemplate = EffectiveTemplates.FindByPredicate(
		[&TemplateId](const FHyperTwistTrainingSessionTemplate& Candidate)
		{
			return Candidate.TemplateId == TemplateId;
		}
	);
	if (MatchingTemplate == nullptr)
	{
		return FHyperTwistTrainingRunState();
	}

	if (HyperTwistTrainingSubsystemInternal::ShouldResumeStoredReviewPlanFromTemplate(
		*MatchingTemplate,
		ActiveReviewPlanState,
		ResolvedUserId))
	{
		FHyperTwistTrainingRunState RunState = StartRecommendedReviewRun(
			SessionId,
			MaterializedDeck.Cases.Num(),
			MatchingTemplate->SuggestedMode
		);
		HyperTwistTrainingSubsystemInternal::PersistActiveRunTemplateLaunchProvenance(
			TrainingRepositoryState,
			ActiveRunState,
			*MatchingTemplate
		);
		if (ActiveRunState.IsStructurallyValid())
		{
			RunState = ActiveRunState;
			RefreshRepositoryViews();
		}
		return RunState;
	}

	FHyperTwistTrainingDeck SourceDeck;
	FHyperTwistTrainingReviewPolicy ReviewPolicy;
	TArray<FHyperTwistTrainingCaseRecommendation> TemplateRecommendations;
	const bool bPreparedReviewTemplateLaunch =
		HyperTwistTrainingSubsystemInternal::TryPrepareReviewPlanBackedTemplateLaunch(
			TrainingRepositoryState,
			*MatchingTemplate,
			MaterializedDeck,
			ResolvedUserId,
			SourceDeck,
			ReviewPolicy,
			TemplateRecommendations
		);

	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
		MaterializedDeck,
		ResolvedUserId,
		SessionId,
		MatchingTemplate->SuggestedMode
	);
	HyperTwistTrainingSubsystemInternal::PersistActiveRunTemplateLaunchProvenance(
		TrainingRepositoryState,
		ActiveRunState,
		*MatchingTemplate
	);
	if (ActiveRunState.IsStructurallyValid())
	{
		RunState = ActiveRunState;
	}
	if (!RunState.IsStructurallyValid()
		|| !MatchingTemplate->bPreferReviewRun
		|| !bPreparedReviewTemplateLaunch)
	{
		if (RunState.IsStructurallyValid())
		{
			RefreshRepositoryViews();
		}
		return RunState;
	}

	ActiveReviewPlanState = UHyperTwistTrainingRepositoryLibrary::BuildReviewPlan(
		SourceDeck,
		MaterializedDeck,
		ResolvedUserId,
		TemplateRecommendations,
		ReviewPolicy,
		FString::Printf(TEXT("review_plan_%s"), *RunState.Session.TrainingSessionId),
		RunState.Session.StartedAtUtc,
		MatchingTemplate->SuggestedMode
	);
	if (ActiveReviewPlanState.IsStructurallyValid())
	{
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertReviewPlan(
			TrainingRepositoryState,
			ActiveReviewPlanState
		);
		ActiveReviewFlowStatus = UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(ActiveReviewPlanState);
		RefreshRepositoryViews();
	}
	else
	{
		ActiveReviewFlowStatus = FHyperTwistTrainingReviewFlowStatus();
	}

	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartActiveMethodDrillFollowUpRun(
	const FString& SessionId
)
{
	if (!ActiveMethodDrillRunState.IsStructurallyValid()
		|| !ActiveMethodDrillFollowUpTemplate.IsStructurallyValid())
	{
		return FHyperTwistTrainingRunState();
	}

	const FHyperTwistTrainingDeck FollowUpDeck = BuildActiveMethodDrillFollowUpDeck();
	if (!FollowUpDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingRunState();
	}

	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;

	if (HyperTwistTrainingSubsystemInternal::ShouldResumeStoredReviewPlanFromTemplate(
		ActiveMethodDrillFollowUpTemplate,
		ActiveReviewPlanState,
		ActiveMethodDrillRunState.UserId))
	{
		FHyperTwistTrainingRunState RunState = StartRecommendedReviewRun(
			StructuredSessionId,
			FollowUpDeck.Cases.Num(),
			ActiveMethodDrillFollowUpTemplate.SuggestedMode
		);
		HyperTwistTrainingSubsystemInternal::PersistActiveRunTemplateLaunchProvenance(
			TrainingRepositoryState,
			ActiveRunState,
			ActiveMethodDrillFollowUpTemplate
		);
		if (ActiveRunState.IsStructurallyValid())
		{
			RunState = ActiveRunState;
			RefreshRepositoryViews();
		}
		return RunState;
	}

	FHyperTwistTrainingDeck SourceDeck;
	FHyperTwistTrainingReviewPolicy ReviewPolicy;
	TArray<FHyperTwistTrainingCaseRecommendation> TemplateRecommendations;
	const bool bPreparedReviewTemplateLaunch =
		HyperTwistTrainingSubsystemInternal::TryPrepareReviewPlanBackedTemplateLaunch(
			TrainingRepositoryState,
			ActiveMethodDrillFollowUpTemplate,
			FollowUpDeck,
			ActiveMethodDrillRunState.UserId,
			SourceDeck,
			ReviewPolicy,
			TemplateRecommendations
		);
	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
		FollowUpDeck,
		ActiveMethodDrillRunState.UserId,
		StructuredSessionId,
		ActiveMethodDrillFollowUpTemplate.SuggestedMode
	);
	HyperTwistTrainingSubsystemInternal::PersistActiveRunTemplateLaunchProvenance(
		TrainingRepositoryState,
		ActiveRunState,
		ActiveMethodDrillFollowUpTemplate
	);
	if (ActiveRunState.IsStructurallyValid())
	{
		RunState = ActiveRunState;
	}
	if (!RunState.IsStructurallyValid()
		|| !ActiveMethodDrillFollowUpTemplate.bPreferReviewRun
		|| !bPreparedReviewTemplateLaunch)
	{
		if (RunState.IsStructurallyValid())
		{
			RefreshRepositoryViews();
		}
		return RunState;
	}

	ActiveReviewPlanState = UHyperTwistTrainingRepositoryLibrary::BuildReviewPlan(
		SourceDeck,
		FollowUpDeck,
		ActiveMethodDrillRunState.UserId,
		TemplateRecommendations,
		ReviewPolicy,
		FString::Printf(TEXT("review_plan_%s"), *RunState.Session.TrainingSessionId),
		RunState.Session.StartedAtUtc,
		ActiveMethodDrillFollowUpTemplate.SuggestedMode
	);
	if (ActiveReviewPlanState.IsStructurallyValid())
	{
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertReviewPlan(
			TrainingRepositoryState,
			ActiveReviewPlanState
		);
		ActiveReviewFlowStatus = UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(
			ActiveReviewPlanState
		);
		RefreshRepositoryViews();
	}
	else
	{
		ActiveReviewFlowStatus = FHyperTwistTrainingReviewFlowStatus();
	}

	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReviewRun(
	const FString& SessionId,
	int32 MaxCases,
	EHyperTwistTrainingDeliveryMode Mode
)
{
	if (!HasActiveRun() && ActiveReviewPlanState.IsStructurallyValid())
	{
		const FHyperTwistTrainingReviewPlanState StoredReviewPlan = ActiveReviewPlanState;
		const FHyperTwistTrainingCoachActionPlan StoredCoachActionPlan = ActiveCoachActionPlan;
		const FHyperTwistCoachBrief StoredCoachBrief = ActiveCoachBrief;
		const FHyperTwistCoachBrief StoredCoachFollowUpBrief = ActiveCoachFollowUpBrief;
		const FHyperTwistTrainingCoachSessionQueueState StoredCoachQueueState = ActiveCoachSessionQueueState;
		const FHyperTwistTrainingDeck ReviewDeck = BuildActiveReviewDeck(MaxCases);
		if (!ReviewDeck.IsStructurallyValid())
		{
			return FHyperTwistTrainingRunState();
		}

		const EHyperTwistTrainingDeliveryMode ResumeMode = StoredReviewPlan.DeliveryMode;
		FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
			ReviewDeck,
			StoredReviewPlan.UserId,
			SessionId,
			ResumeMode
		);
		if (!RunState.IsStructurallyValid())
		{
			return RunState;
		}

		ActiveReviewPlanState = StoredReviewPlan;
		ActiveReviewFlowStatus = UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(
			ActiveReviewPlanState
		);
		if (StoredCoachActionPlan.IsStructurallyValid())
		{
			const FHyperTwistCoachBrief CarryoverResumeBrief =
				HyperTwistTrainingSubsystemInternal::BuildCarryoverReviewResumeBrief(
					StoredReviewPlan,
					StoredCoachActionPlan,
					StoredCoachBrief,
					StoredCoachFollowUpBrief,
					ReviewDeck
				);
			const TArray<FString> LaunchedCaseIds =
				HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(ReviewDeck);
			FHyperTwistTrainingCoachActionPlan DraftActionPlan =
				UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan(
					CarryoverResumeBrief,
					ActiveCoachMemorySnapshot,
					FString::Printf(
						TEXT("coach_carryover_review_%s"),
						*RunState.Session.TrainingSessionId
					),
					RunState.Session.StartedAtUtc,
					ReviewDeck.Cases.Num(),
					ReviewDeck.Cases.Num(),
					TEXT("resume carryover review plan"),
					LaunchedCaseIds
				);
			if (DraftActionPlan.IsStructurallyValid())
			{
				ActiveCoachActionPlan = UHyperTwistTrainingRepositoryLibrary::ActivateCoachActionPlan(
					DraftActionPlan,
					RunState.Session.TrainingSessionId,
					RunState.Session.StartedAtUtc
				);
				TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachActionPlan(
					TrainingRepositoryState,
					ActiveCoachActionPlan
				);
			}
		}
		if (StoredCoachQueueState.IsStructurallyValid())
		{
			FHyperTwistTrainingCoachSessionQueueState RepositoryQueueState;
			const bool bHasRepositoryQueueState =
				UHyperTwistTrainingRepositoryLibrary::TryGetCoachSessionQueueState(
					TrainingRepositoryState,
					StoredCoachQueueState.UserId,
					StoredCoachQueueState.QueueId,
					RepositoryQueueState
				);
			if (bHasRepositoryQueueState)
			{
				const FHyperTwistTrainingCoachSessionQueueStateEntry* ResumeQueueEntry =
					HyperTwistTrainingSubsystemInternal::FindCarryoverResumeQueueEntry(
						RepositoryQueueState,
						StoredReviewPlan,
						StoredCoachActionPlan,
						ReviewDeck
					);
				if (ResumeQueueEntry != nullptr)
				{
					const FHyperTwistTrainingCoachSessionQueueState UpdatedQueueState =
						UHyperTwistTrainingRepositoryLibrary::StartCoachSessionQueueEntryById(
							RepositoryQueueState,
							ResumeQueueEntry->EntryId,
							RunState.Session.TrainingSessionId,
							RunState.Session.StartedAtUtc
						);
					if (UpdatedQueueState.IsStructurallyValid())
					{
						TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
							TrainingRepositoryState,
							UpdatedQueueState
						);
						ActiveCoachSessionQueueState = UpdatedQueueState;
					}
				}
			}
		}
		RefreshRepositoryViews();
		return RunState;
	}

	const FHyperTwistTrainingDeck SourceDeck = ActiveRunState.ActiveDeck;
	const FHyperTwistTrainingReviewPolicy ReviewPolicy =
		HyperTwistTrainingSubsystemInternal::ResolveActiveReviewPolicy(
			ActiveRunState,
			ActiveCoachActionPlan,
			Mode
		);
	const TArray<FHyperTwistTrainingCaseRecommendation> Recommendations =
		UHyperTwistTrainingRepositoryLibrary::ApplyReviewPolicyToRecommendations(
			ActiveCaseRecommendations,
			ReviewPolicy,
			MaxCases
		);
	const FHyperTwistTrainingDeck ReviewDeck = UHyperTwistTrainingRepositoryLibrary::BuildReviewDeckFromRecommendations(
		SourceDeck,
		Recommendations,
		MaxCases
	);
	if (!ReviewDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingRunState();
	}

	const FString UserId = !ActiveCoachBrief.UserId.IsEmpty()
		? ActiveCoachBrief.UserId
		: (!ActiveCoachSessionQueueState.UserId.IsEmpty()
			? ActiveCoachSessionQueueState.UserId
			: (ActiveRunState.Session.UserId.IsEmpty() ? TEXT("local-user") : ActiveRunState.Session.UserId));
	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(ReviewDeck, UserId, SessionId, Mode);
	if (!RunState.IsStructurallyValid())
	{
		return RunState;
	}

	ActiveReviewPlanState = UHyperTwistTrainingRepositoryLibrary::BuildReviewPlan(
		SourceDeck,
		ReviewDeck,
		UserId,
		Recommendations,
		ReviewPolicy,
		FString::Printf(TEXT("review_plan_%s"), *RunState.Session.TrainingSessionId),
		RunState.Session.StartedAtUtc,
		Mode
	);
	if (ActiveReviewPlanState.IsStructurallyValid())
	{
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertReviewPlan(
			TrainingRepositoryState,
			ActiveReviewPlanState
		);
		ActiveReviewFlowStatus = UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(ActiveReviewPlanState);
		RefreshRepositoryViews();
	}
	else
	{
		ActiveReviewFlowStatus = FHyperTwistTrainingReviewFlowStatus();
	}
	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachRecommendedRun(
	const FString& SessionId,
	int32 MaxCases,
	const FString& StartActionSourceLabel
)
{
	const FHyperTwistTrainingDeck CoachDeck = BuildActiveCoachRecommendedDeck(MaxCases);
	if (!CoachDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingRunState();
	}

	const FString UserId = !ActiveCoachBrief.UserId.IsEmpty()
		? ActiveCoachBrief.UserId
		: (!ActiveCoachSessionQueueState.UserId.IsEmpty()
			? ActiveCoachSessionQueueState.UserId
			: (ActiveRunState.Session.UserId.IsEmpty() ? TEXT("local-user") : ActiveRunState.Session.UserId));
	const FHyperTwistTrainingCoachSessionQueueState QueueStateBeforeStart = ActiveCoachSessionQueueState;
	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget LaunchBudget =
		HyperTwistTrainingSubsystemInternal::ResolvePreferredCoachCaseBudget(
			MaxCases,
			EHyperTwistTrainingCoachGuidanceLane::Recommended,
			ActiveCoachMemorySnapshot,
			false
		);
	const TArray<FString> LaunchedCaseIds =
		HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(CoachDeck);
	const FHyperTwistTrainingCoachActionPlan DraftActionPlan =
		UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan(
			ActiveCoachBrief,
			ActiveCoachMemorySnapshot,
			FString::Printf(TEXT("coach_plan_%s"), *SessionId),
			FString(),
			LaunchBudget.RequestedCaseCount,
			CoachDeck.Cases.Num(),
			LaunchBudget.ReasonLine,
			LaunchedCaseIds
		);
	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
		CoachDeck,
		UserId,
		SessionId,
		ActiveCoachBrief.SuggestedMode
	);
	if (!RunState.IsStructurallyValid() || !DraftActionPlan.IsStructurallyValid())
	{
		return RunState;
	}

	ActiveCoachActionPlan = UHyperTwistTrainingRepositoryLibrary::ActivateCoachActionPlan(
		DraftActionPlan,
		RunState.Session.TrainingSessionId,
		RunState.Session.StartedAtUtc
	);
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachActionPlan(
		TrainingRepositoryState,
		ActiveCoachActionPlan
	);
	if (QueueStateBeforeStart.IsStructurallyValid())
	{
		const FHyperTwistTrainingCoachSessionQueueState UpdatedQueueState =
			UHyperTwistTrainingRepositoryLibrary::StartCoachSessionQueueEntryBySourceLabel(
				QueueStateBeforeStart,
				TEXT("primary-brief"),
				RunState.Session.TrainingSessionId,
				RunState.Session.StartedAtUtc,
				StartActionSourceLabel
			);
		if (UpdatedQueueState.IsStructurallyValid())
		{
			TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
				TrainingRepositoryState,
				UpdatedQueueState
			);
			ActiveCoachSessionQueueState = UpdatedQueueState;
		}
	}
	RefreshRepositoryViews();
	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachFollowUpRun(
	const FString& SessionId,
	int32 MaxCases,
	const FString& StartActionSourceLabel
)
{
	const FHyperTwistTrainingDeck FollowUpDeck = BuildActiveCoachFollowUpDeck(MaxCases);
	if (!FollowUpDeck.IsStructurallyValid() || ActiveCoachFollowUpBrief.UserId.IsEmpty())
	{
		return FHyperTwistTrainingRunState();
	}

	const FHyperTwistCoachBrief FollowUpBrief = ActiveCoachFollowUpBrief;
	const FHyperTwistTrainingCoachSessionQueueState QueueStateBeforeStart = ActiveCoachSessionQueueState;
	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget LaunchBudget =
		HyperTwistTrainingSubsystemInternal::ResolvePreferredCoachCaseBudget(
			MaxCases,
			EHyperTwistTrainingCoachGuidanceLane::FollowUp,
			ActiveCoachMemorySnapshot,
			false
		);
	const TArray<FString> LaunchedCaseIds =
		HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(FollowUpDeck);
	const FString AlignedPacketStructureToken =
		HyperTwistTrainingSubsystemInternal::ResolveAlignedCoachFollowUpPacketStructureToken(
			ActiveCoachMemorySnapshot);
	const FString StructuredSessionId = !AlignedPacketStructureToken.IsEmpty()
		? (!SessionId.IsEmpty()
			? FString::Printf(TEXT("%s__%s"), *SessionId, *AlignedPacketStructureToken)
			: FString::Printf(TEXT("coach_follow_up__%s"), *AlignedPacketStructureToken))
		: SessionId;
	const FHyperTwistTrainingCoachActionPlan DraftActionPlan =
		UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan(
			FollowUpBrief,
			ActiveCoachMemorySnapshot,
			FString::Printf(TEXT("coach_follow_up_%s"), *StructuredSessionId),
			FString(),
			LaunchBudget.RequestedCaseCount,
			FollowUpDeck.Cases.Num(),
			LaunchBudget.ReasonLine,
			LaunchedCaseIds
		);
	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
		FollowUpDeck,
		FollowUpBrief.UserId,
		StructuredSessionId,
		FollowUpBrief.SuggestedMode
	);
	if (!RunState.IsStructurallyValid() || !DraftActionPlan.IsStructurallyValid())
	{
		return RunState;
	}

	ActiveCoachActionPlan = UHyperTwistTrainingRepositoryLibrary::ActivateCoachActionPlan(
		DraftActionPlan,
		RunState.Session.TrainingSessionId,
		RunState.Session.StartedAtUtc
	);
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachActionPlan(
		TrainingRepositoryState,
		ActiveCoachActionPlan
	);
	if (QueueStateBeforeStart.IsStructurallyValid())
	{
		const FHyperTwistTrainingCoachSessionQueueState UpdatedQueueState =
			UHyperTwistTrainingRepositoryLibrary::StartCoachSessionQueueEntryBySourceLabel(
				QueueStateBeforeStart,
				TEXT("follow-up-brief"),
				RunState.Session.TrainingSessionId,
				RunState.Session.StartedAtUtc,
				StartActionSourceLabel
			);
		if (UpdatedQueueState.IsStructurallyValid())
		{
			TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
				TrainingRepositoryState,
				UpdatedQueueState
			);
			ActiveCoachSessionQueueState = UpdatedQueueState;
		}
	}
	RefreshRepositoryViews();
	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartPrimaryCoachAction(
	const FString& SessionId,
	int32 MaxCases,
	const FString& StartActionSourceLabel
)
{
	const FHyperTwistTrainingCoachPanelState PanelState = GetActiveCoachPanelState();
	if (PanelState.bCanStartQueuedRun)
	{
		return StartNextQueuedCoachRun(SessionId, MaxCases, StartActionSourceLabel);
	}
	if (PanelState.bCanStartCoachFollowUpRun && PanelState.bHasFollowUpGuidance)
	{
		return StartCoachFollowUpRun(SessionId, MaxCases, StartActionSourceLabel);
	}
	if (PanelState.bCanStartCoachRecommendedRun)
	{
		return StartCoachRecommendedRun(SessionId, MaxCases, StartActionSourceLabel);
	}

	return FHyperTwistTrainingRunState();
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartNextQueuedCoachRun(
	const FString& SessionId,
	int32 MaxCases,
	const FString& StartActionSourceLabel
)
{
	const FHyperTwistTrainingCoachSessionQueueStateEntry* NextRunnableEntry =
		HyperTwistTrainingSubsystemInternal::FindNextRunnableCoachQueueEntry(ActiveCoachSessionQueueState);
	if (NextRunnableEntry == nullptr)
	{
		return FHyperTwistTrainingRunState();
	}

	const FHyperTwistTrainingDeck QueueDeck = HyperTwistTrainingSubsystemInternal::BuildCoachQueueDeckFromEntry(
		*NextRunnableEntry,
		ActiveRunState,
		ActiveCoachMemorySnapshot,
		MaxCases
	);
	if (!QueueDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingRunState();
	}

	const FString UserId = !ActiveCoachSessionQueueState.UserId.IsEmpty()
		? ActiveCoachSessionQueueState.UserId
		: (ActiveRunState.Session.UserId.IsEmpty() ? TEXT("local-user") : ActiveRunState.Session.UserId);
	const FHyperTwistTrainingCoachSessionQueueState QueueStateBeforeStart = ActiveCoachSessionQueueState;
	const FHyperTwistCoachBrief QueueBrief = HyperTwistTrainingSubsystemInternal::BuildCoachBriefFromQueueEntry(
		QueueStateBeforeStart,
		*NextRunnableEntry,
		QueueStateBeforeStart.ReferenceUtc
	);
	const HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget LaunchBudget =
		HyperTwistTrainingSubsystemInternal::ResolveQueueLaunchBudgetFromEntry(
			*NextRunnableEntry,
			QueueDeck,
			ActiveCoachMemorySnapshot,
			MaxCases
		);
	const TArray<FString> LaunchedCaseIds =
		HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(QueueDeck);
	const FHyperTwistTrainingCoachActionPlan DraftActionPlan =
		UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan(
			QueueBrief,
			ActiveCoachMemorySnapshot,
			FString::Printf(TEXT("coach_queue_%s_%s"), *NextRunnableEntry->EntryId, *SessionId),
			FString(),
			LaunchBudget.RequestedCaseCount,
			QueueDeck.Cases.Num(),
			LaunchBudget.ReasonLine,
			LaunchedCaseIds
		);
	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
		QueueDeck,
		UserId,
		SessionId,
		NextRunnableEntry->SuggestedMode
	);
	if (!RunState.IsStructurallyValid())
	{
		return RunState;
	}

	if (DraftActionPlan.IsStructurallyValid())
	{
		ActiveCoachActionPlan = UHyperTwistTrainingRepositoryLibrary::ActivateCoachActionPlan(
			DraftActionPlan,
			RunState.Session.TrainingSessionId,
			RunState.Session.StartedAtUtc
		);
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachActionPlan(
			TrainingRepositoryState,
			ActiveCoachActionPlan
		);
	}

	if (QueueStateBeforeStart.IsStructurallyValid())
	{
		const FHyperTwistTrainingCoachSessionQueueState UpdatedQueueState =
			UHyperTwistTrainingRepositoryLibrary::StartCoachSessionQueueEntryBySourceLabel(
				QueueStateBeforeStart,
				NextRunnableEntry->SourceLabel,
				RunState.Session.TrainingSessionId,
				RunState.Session.StartedAtUtc,
				StartActionSourceLabel
			);
		if (UpdatedQueueState.IsStructurallyValid())
		{
			TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
				TrainingRepositoryState,
				UpdatedQueueState
			);
			ActiveCoachSessionQueueState = UpdatedQueueState;
		}
	}

	RefreshRepositoryViews();
	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachQueueEntry(
	const FString& EntryId,
	const FString& SessionId,
	int32 MaxCases
)
{
	const FHyperTwistTrainingCoachSessionQueueStateEntry* SelectedEntry =
		HyperTwistTrainingSubsystemInternal::FindCoachQueueEntryById(ActiveCoachSessionQueueState, EntryId);
	if (SelectedEntry == nullptr)
	{
		return FHyperTwistTrainingRunState();
	}

	const bool bIsRunnable = SelectedEntry->EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Ready
		|| (SelectedEntry->EntryState == EHyperTwistTrainingCoachSessionQueueEntryState::Pending
			&& SelectedEntry->bCanStartImmediately);
	if (!bIsRunnable)
	{
		return FHyperTwistTrainingRunState();
	}

	FHyperTwistTrainingDeck QueueDeck;
	FHyperTwistCoachBrief QueueBrief;
	HyperTwistTrainingSubsystemInternal::FResolvedCoachCaseBudget LaunchBudget;
	FString UserId = !ActiveCoachSessionQueueState.UserId.IsEmpty()
		? ActiveCoachSessionQueueState.UserId
		: (ActiveRunState.Session.UserId.IsEmpty() ? TEXT("local-user") : ActiveRunState.Session.UserId);

	QueueDeck = HyperTwistTrainingSubsystemInternal::BuildCoachQueueDeckFromEntry(
		*SelectedEntry,
		ActiveRunState,
		ActiveCoachMemorySnapshot,
		MaxCases
	);
	LaunchBudget = HyperTwistTrainingSubsystemInternal::ResolveQueueLaunchBudgetFromEntry(
		*SelectedEntry,
		QueueDeck,
		ActiveCoachMemorySnapshot,
		MaxCases
	);
	QueueBrief = HyperTwistTrainingSubsystemInternal::BuildCoachBriefFromQueueEntry(
		ActiveCoachSessionQueueState,
		*SelectedEntry,
		ActiveCoachSessionQueueState.ReferenceUtc
	);
	UserId = QueueBrief.UserId.IsEmpty() ? UserId : QueueBrief.UserId;

	if (!QueueDeck.IsStructurallyValid())
	{
		return FHyperTwistTrainingRunState();
	}

	const FHyperTwistTrainingCoachSessionQueueState QueueStateBeforeStart = ActiveCoachSessionQueueState;
	const TArray<FString> LaunchedCaseIds =
		HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(QueueDeck);
	const FHyperTwistTrainingCoachActionPlan DraftActionPlan =
		(!QueueBrief.UserId.IsEmpty() && !QueueBrief.Headline.IsEmpty())
			? UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan(
				QueueBrief,
				ActiveCoachMemorySnapshot,
				FString::Printf(TEXT("coach_queue_%s_%s"), *SelectedEntry->EntryId, *SessionId),
				FString(),
				LaunchBudget.RequestedCaseCount,
				QueueDeck.Cases.Num(),
				LaunchBudget.ReasonLine,
				LaunchedCaseIds
			)
			: FHyperTwistTrainingCoachActionPlan();
	FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
		QueueDeck,
		UserId,
		SessionId,
		SelectedEntry->SuggestedMode
	);
	if (!RunState.IsStructurallyValid())
	{
		return RunState;
	}

	if (DraftActionPlan.IsStructurallyValid())
	{
		ActiveCoachActionPlan = UHyperTwistTrainingRepositoryLibrary::ActivateCoachActionPlan(
			DraftActionPlan,
			RunState.Session.TrainingSessionId,
			RunState.Session.StartedAtUtc
		);
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachActionPlan(
			TrainingRepositoryState,
			ActiveCoachActionPlan
		);
	}

	if (QueueStateBeforeStart.IsStructurallyValid())
	{
		const FHyperTwistTrainingCoachSessionQueueState UpdatedQueueState =
			UHyperTwistTrainingRepositoryLibrary::StartCoachSessionQueueEntryById(
				QueueStateBeforeStart,
				SelectedEntry->EntryId,
				RunState.Session.TrainingSessionId,
				RunState.Session.StartedAtUtc
			);
		if (UpdatedQueueState.IsStructurallyValid())
		{
			TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
				TrainingRepositoryState,
				UpdatedQueueState
			);
			ActiveCoachSessionQueueState = UpdatedQueueState;
		}
	}

	RefreshRepositoryViews();
	return RunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromDeck(
	const FHyperTwistTrainingDeck& Deck,
	const FString& UserId,
	const FString& SessionId,
	EHyperTwistTrainingDeliveryMode Mode
)
{
	if (ActiveRecognitionSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveRecognitionSession(CloseError);
	}
	ResetRecognitionSessionState();
	ActiveReviewPlanState = FHyperTwistTrainingReviewPlanState();
	ActiveReviewFlowStatus = FHyperTwistTrainingReviewFlowStatus();
	ActiveCoachActionPlan = FHyperTwistTrainingCoachActionPlan();
	ActiveCoachFollowUpBrief = FHyperTwistCoachBrief();
	ActiveImportedGeneratedModeLaunchRequest = FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
	RetainedRepositoryViewUserId.Reset();
	RetainedRepositoryViewDeckId.Reset();
	RetainedRepositoryViewReferenceUtc.Reset();
	ResetActiveLiveTimerState();
	ActiveRunState = UHyperTwistTrainingLibrary::StartTrainingRun(Deck, UserId, SessionId, Mode);
	ActiveRunState.ImportedGeneratedModeLaunchRequest = ActiveImportedGeneratedModeLaunchRequest;
	bHasActiveRun = ActiveRunState.IsStructurallyValid();
	if (bHasActiveRun && Mode == EHyperTwistTrainingDeliveryMode::RecognitionAssisted)
	{
		FString RecognitionOpenError;
		OpenActiveRecognitionSession(RecognitionOpenError);
	}
	RefreshSummary();
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	RefreshRepositoryViews();
	return ActiveRunState;
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromImportedDeckId(
	const FString& DeckId,
	const FString& UserId,
	const FString& SessionId,
	EHyperTwistTrainingDeliveryMode Mode
)
{
	FHyperTwistTrainingDeck ImportedDeck;
	FHyperTwistTrainingCatalogImportLoadReport LoadReport;
	if (!UHyperTwistTrainingCatalogLibrary::TryMaterializeImportedDeckFromBundledCatalog(
			DeckId,
			ImportedDeck,
			LoadReport))
	{
		ClearActiveRun();
		return ActiveRunState;
	}

	return StartTrainingRunFromDeck(ImportedDeck, UserId, SessionId, Mode);
}

FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartSampleClassicTrainingRun(
	const FString& UserId,
	const FString& SessionId,
	EHyperTwistTrainingDeliveryMode Mode
)
{
	const FHyperTwistContentPack ContentPack = UHyperTwistTrainingCatalogLibrary::MakeAlgTrainerStarterContentPack();
	FHyperTwistTrainingDeck DefaultDeck;
	if (!UHyperTwistTrainingCatalogLibrary::TryGetDefaultDeckFromContentPack(ContentPack, DefaultDeck))
	{
		ClearActiveRun();
		return ActiveRunState;
	}

	return StartTrainingRunFromDeck(DefaultDeck, UserId, SessionId, Mode);
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::StartMethodDrillRun(
	const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
	const FString& UserId,
	const FString& RunId
)
{
	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::StartMethodDrillRun(DrillDefinition, UserId, RunId);
	bHasActiveMethodDrillRun = ActiveMethodDrillRunState.IsStructurallyValid();
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::StartMethodDrillRunFromDeck(
	const FHyperTwistTrainingDeck& Deck,
	const FString& UserId,
	const FString& RunId,
	EHyperTwistTrainingDrillModeKind DrillMode,
	EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
	bool bAnswerHiddenUntilReveal
)
{
	const FHyperTwistTrainingMethodDrillDefinition DrillDefinition =
		UHyperTwistTrainingLibrary::BuildMethodDrillDefinitionFromDeck(
			Deck,
			DrillMode,
			VisibilityPolicy,
			bAnswerHiddenUntilReveal,
			EHyperTwistTrainingDrillEntrySource::Catalog
		);
	return StartMethodDrillRun(DrillDefinition, UserId, RunId);
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::ResumeMethodDrillRunFromBatch(
	const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
	const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
	const FString& RunId
)
{
	const FHyperTwistTrainingMethodDrillBatch RebuiltBatch =
		UHyperTwistTrainingRepositoryLibrary::RebuildDrillBatchForResume(DrillBatch, DrillDefinition);
	if (!RebuiltBatch.IsStructurallyValid())
	{
		ActiveMethodDrillRunState = FHyperTwistTrainingMethodDrillRunState();
		bHasActiveMethodDrillRun = false;
		RefreshMethodDrillSummary();
		return ActiveMethodDrillRunState;
	}

	const FHyperTwistTrainingMethodDrillBatchReadiness Readiness =
		UHyperTwistTrainingRepositoryLibrary::DeriveDrillBatchReadiness(RebuiltBatch, DrillDefinition);
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillBatch(
		TrainingRepositoryState,
		RebuiltBatch
	);
	RefreshRepositoryViews();

	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::ResumeMethodDrillRunFromBatch(
		DrillDefinition,
		RebuiltBatch,
		RunId
	);
	if (ActiveMethodDrillRunState.IsStructurallyValid()
		&& !Readiness.bIsResumable
		&& ActiveMethodDrillRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Completed
		&& ActiveMethodDrillRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Aborted)
	{
		ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::FinishMethodDrillRun(
			ActiveMethodDrillRunState,
			false
		);
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillBatch(
			TrainingRepositoryState,
			UHyperTwistTrainingLibrary::BuildMethodDrillBatch(
				ActiveMethodDrillRunState,
				RebuiltBatch.BatchId,
				RebuiltBatch.Title,
				RebuiltBatch.bPinnedFavoritesOnly
			)
		);
		RefreshRepositoryViews();
	}
	bHasActiveMethodDrillRun = ActiveMethodDrillRunState.IsStructurallyValid();
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::StartNextActiveMethodDrillCase()
{
	if (!HasActiveMethodDrillRun())
	{
		return FHyperTwistTrainingMethodDrillRunState();
	}

	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::StartNextMethodDrillCase(ActiveMethodDrillRunState);
	bHasActiveMethodDrillRun = ActiveMethodDrillRunState.IsStructurallyValid();
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::RevealActiveMethodDrillCase()
{
	if (!HasActiveMethodDrillRun())
	{
		return FHyperTwistTrainingMethodDrillRunState();
	}

	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::RevealMethodDrillCase(ActiveMethodDrillRunState);
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::RepeatActiveMethodDrillCase()
{
	if (!HasActiveMethodDrillRun())
	{
		return FHyperTwistTrainingMethodDrillRunState();
	}

	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::RepeatMethodDrillCase(ActiveMethodDrillRunState);
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::AdvanceActiveMethodDrillCase()
{
	if (!HasActiveMethodDrillRun())
	{
		return FHyperTwistTrainingMethodDrillRunState();
	}

	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::AdvanceMethodDrillCase(ActiveMethodDrillRunState);
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::FinishActiveMethodDrillRun(bool bAbortRun)
{
	if (!HasActiveMethodDrillRun())
	{
		return FHyperTwistTrainingMethodDrillRunState();
	}

	ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::FinishMethodDrillRun(
		ActiveMethodDrillRunState,
		bAbortRun
	);
	RefreshMethodDrillSummary();
	return ActiveMethodDrillRunState;
}

FHyperTwistTrainingRunStepResult UHyperTwistTrainingSubsystem::SubmitTrainingAttempt(
	const FHyperTwistTrainingAttempt& Attempt,
	int32 TimeMs
)
{
	FHyperTwistTrainingRunStepResult StepResult;
	StepResult.UpdatedRunState = ActiveRunState;

	if (!HasActiveRun())
	{
		return StepResult;
	}

	StepResult = UHyperTwistTrainingLibrary::ResolveTrainingRunAttempt(
		ActiveRunState,
		Attempt,
		TimeMs
	);
	if (!StepResult.IsStructurallyValid())
	{
		return StepResult;
	}

	ActiveRunState = StepResult.UpdatedRunState;
	bHasActiveRun = ActiveRunState.IsStructurallyValid();
	ActiveRunSummary = StepResult.SessionSummary;
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	if (ActiveReviewPlanState.IsStructurallyValid())
	{
		ActiveReviewPlanState = UHyperTwistTrainingRepositoryLibrary::UpdateReviewPlanAfterAttempt(
			ActiveReviewPlanState,
			StepResult,
			Attempt
		);
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertReviewPlan(
			TrainingRepositoryState,
			ActiveReviewPlanState
		);
		ActiveReviewFlowStatus = UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(ActiveReviewPlanState);
	}
	RefreshRepositoryViews();
	return StepResult;
}

bool UHyperTwistTrainingSubsystem::StartActiveLiveTimer()
{
	if (HasActiveLiveTimer())
	{
		if (ActiveLiveTimerState.Phase == EHyperTwistTrainingLiveTimerPhase::Inspection)
		{
			return AdvanceActiveLiveTimerToSolvePhase();
		}
		if (ActiveLiveTimerState.Phase == EHyperTwistTrainingLiveTimerPhase::Solving)
		{
			return PauseActiveLiveTimer();
		}
		if (ActiveLiveTimerState.Phase == EHyperTwistTrainingLiveTimerPhase::Paused)
		{
			return ResumeActiveLiveTimer();
		}
	}

	if (!HasActiveRun()
		|| !ActiveRunState.Session.IsStructurallyValid()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
	{
		return false;
	}

	const FHyperTwistTrainingTimingPolicy TimingPolicy =
		UHyperTwistTrainingLibrary::NormalizeTimingPolicy(ActiveRunState.ActiveDeck.TimingPolicy);
	const bool bUseInspection = TimingPolicy.bInspectionEnabled && TimingPolicy.InspectionDurationMs > 0;
	const double NowSeconds = FPlatformTime::Seconds();
	const FString NowUtc = FDateTime::UtcNow().ToIso8601();

	ResetActiveLiveTimerState();
	ActiveLiveTimerState.TrainingSessionId = ActiveRunState.Session.TrainingSessionId;
	ActiveLiveTimerState.UserId = ActiveRunState.Session.UserId;
	ActiveLiveTimerState.DeckId = !ActiveRunState.ActiveDeck.DeckId.IsEmpty()
		? ActiveRunState.ActiveDeck.DeckId
		: ActiveRunState.Session.DeckId;
	ActiveLiveTimerState.CaseId = ActiveRunState.CurrentSelection.TrainingCase.CaseId;
	ActiveLiveTimerState.StartedAtUtc = NowUtc;
	ActiveLiveTimerState.LastUpdatedAtUtc = NowUtc;
	ActiveLiveTimerState.Phase = bUseInspection
		? EHyperTwistTrainingLiveTimerPhase::Inspection
		: EHyperTwistTrainingLiveTimerPhase::Solving;
	ActiveLiveTimerState.ResumePhase = ActiveLiveTimerState.Phase;
	ActiveLiveTimerState.TimingPolicy = TimingPolicy;
	ActiveLiveTimerState.bHasInspectionWindow = bUseInspection;
	ActiveLiveTimerState.InspectionLimitMs = bUseInspection ? FMath::Max(TimingPolicy.InspectionDurationMs, 0) : 0;
	ActiveLiveTimerState.bHideRunningTime = TimingPolicy.bHideRunningTime;
	ActiveLiveTimerStartedAtSeconds = NowSeconds;
	ActiveLiveTimerSolveStartedAtSeconds = bUseInspection ? 0.0 : NowSeconds;
	RefreshActiveLiveTimerState();
	return HasActiveLiveTimer();
}

bool UHyperTwistTrainingSubsystem::AdvanceActiveLiveTimerToSolvePhase()
{
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer() || ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Inspection)
	{
		return false;
	}

	ActiveLiveTimerStoredInspectionElapsedMs = ActiveLiveTimerState.InspectionElapsedMs;
	ActiveLiveTimerStoredSolveElapsedMs = 0;
	ActiveLiveTimerSolveStartedAtSeconds = FPlatformTime::Seconds();
	ActiveLiveTimerPausedAtSeconds = 0.0;
	ActiveLiveTimerState.Phase = EHyperTwistTrainingLiveTimerPhase::Solving;
	ActiveLiveTimerState.ResumePhase = EHyperTwistTrainingLiveTimerPhase::Solving;
	RefreshActiveLiveTimerState();
	return true;
}

bool UHyperTwistTrainingSubsystem::PauseActiveLiveTimer()
{
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer() || ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Solving)
	{
		return false;
	}

	ActiveLiveTimerStoredInspectionElapsedMs = ActiveLiveTimerState.InspectionElapsedMs;
	ActiveLiveTimerStoredSolveElapsedMs = ActiveLiveTimerState.SolveElapsedMs;
	ActiveLiveTimerPausedAtSeconds = FPlatformTime::Seconds();
	ActiveLiveTimerState.Phase = EHyperTwistTrainingLiveTimerPhase::Paused;
	ActiveLiveTimerState.ResumePhase = EHyperTwistTrainingLiveTimerPhase::Solving;
	RefreshActiveLiveTimerState();

	if (ActiveRunState.ReplayPacket.ReplayId.Len() > 0)
	{
		FHyperTwistReplayEvent ReplayEvent;
		ReplayEvent.EventType = EHyperTwistReplayEventType::Pause;
		ReplayEvent.TimeMs = HyperTwistTrainingSubsystemInternal::ResolveLiveTimerReplayTimeMs(ActiveLiveTimerState);
		ActiveRunState.ReplayPacket = UHyperTwistReplayLibrary::AppendReplayEvent(ActiveRunState.ReplayPacket, ReplayEvent);
		ActiveRunState.LastReplayEvent = ActiveRunState.ReplayPacket.Events.Last();
	}

	return true;
}

bool UHyperTwistTrainingSubsystem::ResumeActiveLiveTimer()
{
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer() || ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Paused)
	{
		return false;
	}

	const double NowSeconds = FPlatformTime::Seconds();
	if (ActiveLiveTimerPausedAtSeconds > 0.0)
	{
		ActiveLiveTimerState.TotalPausedMs += FMath::Max(
			0,
			static_cast<int32>((NowSeconds - ActiveLiveTimerPausedAtSeconds) * 1000.0)
		);
	}

	const EHyperTwistTrainingLiveTimerPhase ResumePhase =
		ActiveLiveTimerState.ResumePhase == EHyperTwistTrainingLiveTimerPhase::Idle
			? EHyperTwistTrainingLiveTimerPhase::Solving
			: ActiveLiveTimerState.ResumePhase;
	if (ResumePhase == EHyperTwistTrainingLiveTimerPhase::Inspection)
	{
		ActiveLiveTimerStartedAtSeconds = NowSeconds;
	}
	else
	{
		ActiveLiveTimerSolveStartedAtSeconds = NowSeconds;
	}

	ActiveLiveTimerPausedAtSeconds = 0.0;
	ActiveLiveTimerState.Phase = ResumePhase;
	ActiveLiveTimerState.ResumePhase = ResumePhase;
	RefreshActiveLiveTimerState();

	if (ActiveRunState.ReplayPacket.ReplayId.Len() > 0)
	{
		FHyperTwistReplayEvent ReplayEvent;
		ReplayEvent.EventType = EHyperTwistReplayEventType::Resume;
		ReplayEvent.TimeMs = HyperTwistTrainingSubsystemInternal::ResolveLiveTimerReplayTimeMs(ActiveLiveTimerState);
		ActiveRunState.ReplayPacket = UHyperTwistReplayLibrary::AppendReplayEvent(ActiveRunState.ReplayPacket, ReplayEvent);
		ActiveRunState.LastReplayEvent = ActiveRunState.ReplayPacket.Events.Last();
	}

	return true;
}

void UHyperTwistTrainingSubsystem::CancelActiveLiveTimer()
{
	ResetActiveLiveTimerState();
}

bool UHyperTwistTrainingSubsystem::CaptureActiveLiveTimerSplit()
{
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer() || ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Solving)
	{
		return false;
	}

	const int32 MaxManualSplitCaptureCount =
		ActiveLiveTimerState.TimingPolicy.SplitPhases.Num() > 1
			? ActiveLiveTimerState.TimingPolicy.SplitPhases.Num() - 1
			: 0;
	const int32 NextPhaseIndex = ActiveLiveTimerState.SplitCaptures.Num();
	if (MaxManualSplitCaptureCount <= 0
		|| NextPhaseIndex >= MaxManualSplitCaptureCount
		|| !ActiveLiveTimerState.TimingPolicy.SplitPhases.IsValidIndex(NextPhaseIndex))
	{
		return false;
	}

	const FHyperTwistTrainingSplitPhaseDefinition& NextPhaseDefinition =
		ActiveLiveTimerState.TimingPolicy.SplitPhases[NextPhaseIndex];
	FHyperTwistTrainingSplitCapture SplitCapture;
	SplitCapture.PhaseId = NextPhaseDefinition.PhaseId;
	SplitCapture.Label = NextPhaseDefinition.Label;
	SplitCapture.TimestampMs = FMath::Max(ActiveLiveTimerState.SolveElapsedMs, 0);
	ActiveLiveTimerState.SplitCaptures.Add(SplitCapture);
	ActiveLiveTimerState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	return true;
}

bool UHyperTwistTrainingSubsystem::UndoActiveLiveTimerSplit()
{
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer()
		|| (ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Solving
			&& ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Paused)
		|| ActiveLiveTimerState.SplitCaptures.Num() <= 0)
	{
		return false;
	}

	ActiveLiveTimerState.SplitCaptures.RemoveAt(ActiveLiveTimerState.SplitCaptures.Num() - 1);
	ActiveLiveTimerState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	return true;
}

FHyperTwistTrainingRunStepResult UHyperTwistTrainingSubsystem::SubmitActiveLiveTimedAttempt(
	const EHyperTwistTrainingAttemptResult Result
)
{
	FHyperTwistTrainingRunStepResult StepResult;
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer()
		|| (ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Solving
			&& ActiveLiveTimerState.Phase != EHyperTwistTrainingLiveTimerPhase::Paused)
		|| !HasActiveRun()
		|| !ActiveRunState.Session.IsStructurallyValid()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
	{
		return StepResult;
	}

	FHyperTwistTrainingAttempt Attempt;
	Attempt.AttemptId = FString::Printf(
		TEXT("attempt_%s_%s"),
		*ActiveRunState.Session.TrainingSessionId,
		*FGuid::NewGuid().ToString(EGuidFormats::Digits)
	);
	Attempt.TrainingSessionId = ActiveRunState.Session.TrainingSessionId;
	Attempt.CaseId = ActiveRunState.CurrentSelection.TrainingCase.CaseId;
	Attempt.Result = Result;
	Attempt.TotalTimeMs = FMath::Max(ActiveLiveTimerState.SolveElapsedMs, 0);
	Attempt.ExecutionTimeMs = FMath::Max(ActiveLiveTimerState.SolveElapsedMs, 0);
	Attempt.TimingBreakdown.InspectionElapsedMs = FMath::Max(ActiveLiveTimerState.InspectionElapsedMs, 0);
	Attempt.TimingBreakdown.RawSolveTimeMs = FMath::Max(ActiveLiveTimerState.SolveElapsedMs, 0);
	Attempt.TimingBreakdown.FinalTimeMs = FMath::Max(ActiveLiveTimerState.SolveElapsedMs, 0);
	Attempt.TimingBreakdown.InspectionPenalty = ActiveLiveTimerState.InspectionPenalty;
	Attempt.TimingBreakdown.ManualPenalty =
		Result == EHyperTwistTrainingAttemptResult::DNF
			? EHyperTwistTrainingPenalty::DNF
			: ActiveLiveTimerState.ManualPenalty;
	Attempt.TimingBreakdown.AppliedPenalty =
		Result == EHyperTwistTrainingAttemptResult::DNF
			? EHyperTwistTrainingPenalty::DNF
			: ActiveLiveTimerState.PendingPenalty;
	Attempt.TimingBreakdown.SplitCaptures = ActiveLiveTimerState.SplitCaptures;
	Attempt.TimingBreakdown.bDidNotFinish =
		Result == EHyperTwistTrainingAttemptResult::Timeout
		|| Result == EHyperTwistTrainingAttemptResult::DNF
		|| Result == EHyperTwistTrainingAttemptResult::Aborted;
	Attempt.ReplayId = ActiveRunState.ReplayPacket.ReplayId;
	Attempt.CompletedAtUtc = FDateTime::UtcNow().ToIso8601();

	StepResult = SubmitTrainingAttempt(Attempt, FMath::Max(ActiveLiveTimerState.SolveElapsedMs, 0));
	if (StepResult.IsStructurallyValid())
	{
		ResetActiveLiveTimerState();
	}

	return StepResult;
}

FHyperTwistTrainingSession UHyperTwistTrainingSubsystem::CompleteActiveRun(bool bAbortSession)
{
	if (!HasActiveRun())
	{
		return FHyperTwistTrainingSession();
	}

	if (ActiveRecognitionSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveRecognitionSession(CloseError);
	}

	ResetActiveLiveTimerState();

	ActiveRunState.Session = UHyperTwistTrainingLibrary::CompleteTrainingSession(ActiveRunState.Session, bAbortSession);
	ActiveRunState.CurrentSelection = FHyperTwistTrainingCaseSelection();
	ActiveRunState.RemainingCaseIds.Reset();

	if (ActiveRunState.ReplayPacket.ReplayId.Len() > 0)
	{
		ActiveRunState.ReplayPacket.EndedAtUtc = ActiveRunState.Session.EndedAtUtc;
	}

	RefreshSummary();
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	if (ActiveReviewPlanState.IsStructurallyValid())
	{
		ActiveReviewPlanState = UHyperTwistTrainingRepositoryLibrary::FinalizeReviewPlan(
			ActiveReviewPlanState,
			ActiveRunState.Session
		);
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertReviewPlan(
			TrainingRepositoryState,
			ActiveReviewPlanState
		);
		ActiveReviewFlowStatus = UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(ActiveReviewPlanState);
	}
	if (ActiveCoachActionPlan.IsStructurallyValid())
	{
		ActiveCoachActionPlan = UHyperTwistTrainingRepositoryLibrary::FinalizeCoachActionPlan(
			ActiveCoachActionPlan,
			ActiveRunState.Session,
			bAbortSession
		);
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachActionPlan(
			TrainingRepositoryState,
			ActiveCoachActionPlan
		);
	}
	if (ActiveCoachSessionQueueState.IsStructurallyValid())
	{
		ActiveCoachSessionQueueState = UHyperTwistTrainingRepositoryLibrary::FinalizeCoachSessionQueueEntry(
			ActiveCoachSessionQueueState,
			ActiveRunState.Session.TrainingSessionId,
			ActiveRunState.Session.EndedAtUtc,
			bAbortSession
		);
		if (ActiveCoachSessionQueueState.IsStructurallyValid())
		{
			TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
				TrainingRepositoryState,
				ActiveCoachSessionQueueState
			);
		}
	}
	ResetRecognitionSessionState();
	RefreshRepositoryViews();
	return ActiveRunState.Session;
}

void UHyperTwistTrainingSubsystem::ClearActiveRun()
{
	if (ActiveRecognitionSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveRecognitionSession(CloseError);
	}
	ResetActiveLiveTimerState();
	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();
	ActiveReviewPlanState = FHyperTwistTrainingReviewPlanState();
	ActiveCoachActionPlan = FHyperTwistTrainingCoachActionPlan();
	bHasActiveRun = false;
	ResetRecognitionSessionState();
	RefreshRepositoryViews();
}

bool UHyperTwistTrainingSubsystem::OpenActiveRecognitionSession(FString& OutError)
{
	OutError.Reset();

	if (!HasActiveRun())
	{
		OutError = TEXT("no-active-training-run");
		ActiveRecognitionSessionState.LastError = OutError;
		RefreshRecognitionServiceHealth();
		return false;
	}

	IHyperTwistVisionClient* VisionClient = HyperTwistTrainingSubsystemInternal::ResolveVisionClient(
		ResolveRecognitionVisionClientObject()
	);
	if (VisionClient == nullptr)
	{
		OutError = TEXT("recognition-client-unavailable");
		ActiveRecognitionSessionState.LastError = OutError;
		RefreshRecognitionServiceHealth();
		return false;
	}

	const FHyperTwistVisionSessionConfig SessionConfig = BuildActiveRecognitionSessionConfig();
	if (SessionConfig.SessionId.IsEmpty())
	{
		OutError = TEXT("recognition-session-id-unavailable");
		ActiveRecognitionSessionState.LastError = OutError;
		RefreshRecognitionServiceHealth();
		return false;
	}

	if (ActiveRecognitionSessionState.bSessionOpen
		&& ActiveRecognitionSessionState.ActiveSessionId == SessionConfig.SessionId)
	{
		ActiveRecognitionSessionState.SessionConfig = SessionConfig;
		ActiveRecognitionSessionState.LastError.Reset();
		ActiveRecognitionSessionState.ServiceHealth.LastError.Reset();
		return true;
	}

	if (ActiveRecognitionSessionState.bSessionOpen
		&& ActiveRecognitionSessionState.ActiveSessionId != SessionConfig.SessionId)
	{
		FString CloseError;
		VisionClient->CloseVisionSession(ActiveRecognitionSessionState.ActiveSessionId, CloseError);
	}

	if (!VisionClient->OpenVisionSession(SessionConfig, OutError))
	{
		ActiveRecognitionSessionState.LastError = OutError;
		RefreshRecognitionServiceHealth();
		return false;
	}

	const FString OpenedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveRecognitionSessionState.bSessionOpen = true;
	ActiveRecognitionSessionState.bUsingProviderBackedClient =
		ActiveRecognitionVisionClientObject != nullptr
		&& ActiveRecognitionVisionClientObject->IsA<UHyperTwistHttpVisionClient>();
	ActiveRecognitionSessionState.ActiveSessionId = SessionConfig.SessionId;
	ActiveRecognitionSessionState.OpenedAtUtc = OpenedAtUtc;
	ActiveRecognitionSessionState.LastUpdatedAtUtc = OpenedAtUtc;
	ActiveRecognitionSessionState.LastError.Reset();
	ActiveRecognitionSessionState.SessionConfig = SessionConfig;
	ActiveRecognitionSessionState.bHasPreviewResult = false;
	ActiveRecognitionSessionState.bHasCommitResult = false;
	ActiveRecognitionSessionState.LastPreviewResult = FHyperTwistVisionPreviewResult();
	ActiveRecognitionSessionState.LastCommitResult = FHyperTwistVisionCommitResult();
	RefreshRecognitionServiceHealth();
	return true;
}

FHyperTwistVisionPreviewResult UHyperTwistTrainingSubsystem::SubmitActiveRecognitionFrame(
	const FHyperTwistVisionFrameEnvelope& Frame
)
{
	FHyperTwistVisionPreviewResult Result;

	if (!HasActiveRun())
	{
		Result.Guidance = TEXT("no-active-training-run");
		return Result;
	}

	FString OpenError;
	if (!OpenActiveRecognitionSession(OpenError))
	{
		Result.SessionId = !Frame.SessionId.IsEmpty() ? Frame.SessionId : BuildActiveRecognitionSessionConfig().SessionId;
		Result.FrameId = Frame.FrameId;
		Result.Guidance = OpenError.IsEmpty() ? TEXT("recognition-session-open-failed") : OpenError;
		return Result;
	}

	IHyperTwistVisionClient* VisionClient = HyperTwistTrainingSubsystemInternal::ResolveVisionClient(
		ResolveRecognitionVisionClientObject()
	);
	if (VisionClient == nullptr)
	{
		Result.Guidance = TEXT("recognition-client-unavailable");
		ActiveRecognitionSessionState.LastError = Result.Guidance;
		ActiveRecognitionSessionState.ServiceHealth.LastError = ActiveRecognitionSessionState.LastError;
		return Result;
	}

	FHyperTwistVisionFrameEnvelope NormalizedFrame = Frame;
	NormalizedFrame.SessionId = ActiveRecognitionSessionState.ActiveSessionId;
	if (NormalizedFrame.FrameOrdinal <= 0)
	{
		NormalizedFrame.FrameOrdinal = ActiveRecognitionSessionState.SubmittedFrameCount + 1;
	}
	if (NormalizedFrame.FrameId.IsEmpty())
	{
		NormalizedFrame.FrameId = HyperTwistTrainingSubsystemInternal::BuildRecognitionFrameId(
			NormalizedFrame.SessionId,
			NormalizedFrame.FrameOrdinal
		);
	}
	if (NormalizedFrame.CapturedAtUtc.IsEmpty())
	{
		NormalizedFrame.CapturedAtUtc = FDateTime::UtcNow().ToIso8601();
	}

	Result = VisionClient->SubmitVisionFrame(NormalizedFrame);
	if (Result.SessionId.IsEmpty())
	{
		Result.SessionId = NormalizedFrame.SessionId;
	}
	if (Result.FrameId.IsEmpty())
	{
		Result.FrameId = NormalizedFrame.FrameId;
	}
	if (Result.PreviewState.State.SourceSessionId.IsEmpty())
	{
		Result.PreviewState.State.SourceSessionId = NormalizedFrame.SessionId;
	}

	ActiveRecognitionSessionState.bHasPreviewResult = true;
	ActiveRecognitionSessionState.LastPreviewResult = Result;
	ActiveRecognitionSessionState.SubmittedFrameCount = FMath::Max(
		ActiveRecognitionSessionState.SubmittedFrameCount,
		NormalizedFrame.FrameOrdinal
	);
	ActiveRecognitionSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveRecognitionSessionState.LastError.Reset();
	ActiveRecognitionSessionState.ServiceHealth.LastError.Reset();

	FHyperTwistReplayRecognitionPayload Payload;
	Payload.Snapshot = Result.PreviewState;
	Payload.Confidence = Result.PreviewConfidence;
	Payload.ScanStage = NormalizedFrame.CameraPoseHint;
	AppendRecognitionReplayEvent(
		ActiveRecognitionSessionState.SubmittedFrameCount <= 1
			? EHyperTwistReplayEventType::RecognitionPreview
			: EHyperTwistReplayEventType::RecognitionScan,
		Payload,
		NormalizedFrame.SourceTimestampMs > 0 ? NormalizedFrame.SourceTimestampMs : INDEX_NONE
	);
	SynchronizeRecognitionReplayMutation();
	return Result;
}

FHyperTwistVisionCommitResult UHyperTwistTrainingSubsystem::CommitActiveRecognitionObservation(
	const FHyperTwistVisionCommitRequest& Request
)
{
	FHyperTwistVisionCommitResult Result;

	if (!HasActiveRun())
	{
		Result.Warnings.Add(TEXT("no-active-training-run"));
		return Result;
	}

	FString OpenError;
	if (!OpenActiveRecognitionSession(OpenError))
	{
		Result.SessionId = Request.SessionId;
		Result.CommitKind = Request.CommitKind;
		Result.Warnings.Add(OpenError.IsEmpty() ? TEXT("recognition-session-open-failed") : OpenError);
		return Result;
	}

	IHyperTwistVisionClient* VisionClient = HyperTwistTrainingSubsystemInternal::ResolveVisionClient(
		ResolveRecognitionVisionClientObject()
	);
	if (VisionClient == nullptr)
	{
		Result.Warnings.Add(TEXT("recognition-client-unavailable"));
		ActiveRecognitionSessionState.LastError = Result.Warnings[0];
		ActiveRecognitionSessionState.ServiceHealth.LastError = ActiveRecognitionSessionState.LastError;
		return Result;
	}

	FHyperTwistVisionCommitRequest NormalizedRequest = Request;
	NormalizedRequest.SessionId = ActiveRecognitionSessionState.ActiveSessionId;
	if (NormalizedRequest.CommitKind.IsEmpty())
	{
		NormalizedRequest.CommitKind = TEXT("face");
	}

	Result = VisionClient->CommitVisionObservation(NormalizedRequest);
	if (Result.SessionId.IsEmpty())
	{
		Result.SessionId = NormalizedRequest.SessionId;
	}
	if (Result.CommitKind.IsEmpty())
	{
		Result.CommitKind = NormalizedRequest.CommitKind;
	}
	if (Result.Snapshot.State.SourceSessionId.IsEmpty())
	{
		Result.Snapshot.State.SourceSessionId = NormalizedRequest.SessionId;
	}

	const FString ResolvedStage = !Result.CommittedUnit.IsEmpty()
		? Result.CommittedUnit
		: (!NormalizedRequest.TargetStage.IsEmpty() ? NormalizedRequest.TargetStage : NormalizedRequest.TargetFace);
	const bool bHasCorrectionSignals =
		Result.Warnings.Num() > 0 || Result.MissingUnits.Num() > 0;
	const bool bHasCommitSignal =
		!Result.CommittedUnit.IsEmpty()
		|| Result.Snapshot.IsStructurallyValid()
		|| Result.Snapshot.State.IsStructurallyValid()
		|| Result.Confidence > 0.0f;

	if (bHasCorrectionSignals)
	{
		FHyperTwistReplayRecognitionPayload CorrectionPayload;
		CorrectionPayload.Snapshot = Result.Snapshot;
		CorrectionPayload.Confidence = Result.Confidence;
		CorrectionPayload.CommittedFaceOrStage = ResolvedStage;
		AppendRecognitionReplayEvent(
			EHyperTwistReplayEventType::RecognitionCorrection,
			CorrectionPayload,
			INDEX_NONE
		);
		++ActiveRecognitionSessionState.CorrectionEventCount;
	}

	if (bHasCommitSignal)
	{
		FHyperTwistReplayRecognitionPayload CommitPayload;
		CommitPayload.Snapshot = Result.Snapshot;
		CommitPayload.Confidence = Result.Confidence;
		CommitPayload.CommittedFaceOrStage = ResolvedStage;
		AppendRecognitionReplayEvent(
			EHyperTwistReplayEventType::RecognitionCommit,
			CommitPayload,
			INDEX_NONE
		);
		++ActiveRecognitionSessionState.CommittedObservationCount;
	}

	ActiveRecognitionSessionState.bHasCommitResult = true;
	ActiveRecognitionSessionState.LastCommitResult = Result;
	ActiveRecognitionSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveRecognitionSessionState.LastError =
		Result.Warnings.Num() > 0 ? FString::Join(Result.Warnings, TEXT(" | ")) : FString();
	ActiveRecognitionSessionState.ServiceHealth.LastError = ActiveRecognitionSessionState.LastError;

	if (bHasCorrectionSignals || bHasCommitSignal)
	{
		SynchronizeRecognitionReplayMutation();
	}

	return Result;
}

FHyperTwistVisionFinalizeResult UHyperTwistTrainingSubsystem::FinalizeActiveRecognitionSession()
{
	FHyperTwistVisionFinalizeResult Result;

	if (!HasActiveRun())
	{
		Result.NormalizationWarnings.Add(TEXT("no-active-training-run"));
		return Result;
	}

	if (!ActiveRecognitionSessionState.bSessionOpen || ActiveRecognitionSessionState.ActiveSessionId.IsEmpty())
	{
		Result.NormalizationWarnings.Add(TEXT("recognition-session-not-open"));
		return Result;
	}

	IHyperTwistVisionClient* VisionClient = HyperTwistTrainingSubsystemInternal::ResolveVisionClient(
		ResolveRecognitionVisionClientObject()
	);
	if (VisionClient == nullptr)
	{
		Result.NormalizationWarnings.Add(TEXT("recognition-client-unavailable"));
		ActiveRecognitionSessionState.LastError = Result.NormalizationWarnings[0];
		ActiveRecognitionSessionState.ServiceHealth.LastError = ActiveRecognitionSessionState.LastError;
		return Result;
	}

	const FString SessionId = ActiveRecognitionSessionState.ActiveSessionId;
	Result = VisionClient->FinalizeVisionSession(SessionId);
	if (Result.SessionId.IsEmpty())
	{
		Result.SessionId = SessionId;
	}
	if (Result.FinalState.SourceSessionId.IsEmpty())
	{
		Result.FinalState.SourceSessionId = SessionId;
	}
	if (Result.FinalSnapshot.State.SourceSessionId.IsEmpty())
	{
		Result.FinalSnapshot.State.SourceSessionId = SessionId;
	}

	TArray<FHyperTwistReplayEvent> PendingRecognitionEvents;
	for (const FString& SeedJson : Result.ReplaySeedEventsJson)
	{
		FHyperTwistReplayPacket SeedPacket;
		if (HyperTwistTrainingSubsystemInternal::DeserializeStruct(SeedJson, SeedPacket))
		{
			for (const FHyperTwistReplayEvent& Event : SeedPacket.Events)
			{
				if (HyperTwistTrainingSubsystemInternal::IsRecognitionReplayEventType(Event.EventType))
				{
					PendingRecognitionEvents.Add(Event);
				}
			}
			continue;
		}

		FHyperTwistReplayEvent SeedEvent;
		if (HyperTwistTrainingSubsystemInternal::DeserializeStruct(SeedJson, SeedEvent)
			&& HyperTwistTrainingSubsystemInternal::IsRecognitionReplayEventType(SeedEvent.EventType))
		{
			PendingRecognitionEvents.Add(SeedEvent);
		}
	}

	const bool bHadProviderSeedEvents = PendingRecognitionEvents.Num() > 0;
	const bool bHasProviderCorrectionEvent = PendingRecognitionEvents.ContainsByPredicate(
		[](const FHyperTwistReplayEvent& Event)
		{
			return Event.EventType == EHyperTwistReplayEventType::RecognitionCorrection;
		}
	);

	if (Result.NormalizationWarnings.Num() > 0 && !bHasProviderCorrectionEvent)
	{
		FHyperTwistReplayRecognitionPayload CorrectionPayload =
			HyperTwistTrainingSubsystemInternal::BuildFinalizeCorrectionPayload(Result);
		CorrectionPayload.Snapshot = HyperTwistTrainingSubsystemInternal::BuildSnapshotFromFinalState(Result);

		FString CorrectionPayloadJson;
		if (HyperTwistTrainingSubsystemInternal::SerializeStruct(CorrectionPayload, CorrectionPayloadJson))
		{
			FHyperTwistReplayEvent CorrectionEvent;
			CorrectionEvent.EventType = EHyperTwistReplayEventType::RecognitionCorrection;
			CorrectionEvent.TimeMs = PendingRecognitionEvents.Num() > 0
				? PendingRecognitionEvents.Last().TimeMs
				: INDEX_NONE;
			CorrectionEvent.PayloadJson = CorrectionPayloadJson;

			const int32 InsertIndex = PendingRecognitionEvents.IndexOfByPredicate(
				[](const FHyperTwistReplayEvent& Event)
				{
					return Event.EventType == EHyperTwistReplayEventType::RecognitionCommit;
				}
			);
			if (InsertIndex == INDEX_NONE)
			{
				PendingRecognitionEvents.Add(CorrectionEvent);
			}
			else
			{
				PendingRecognitionEvents.Insert(CorrectionEvent, InsertIndex);
			}
			++ActiveRecognitionSessionState.CorrectionEventCount;
		}
	}

	if (!bHadProviderSeedEvents)
	{
		FHyperTwistReplayRecognitionPayload CommitPayload =
			HyperTwistTrainingSubsystemInternal::BuildFinalizeCommitPayload(Result);
		CommitPayload.Snapshot = HyperTwistTrainingSubsystemInternal::BuildSnapshotFromFinalState(Result);

		FString CommitPayloadJson;
		if (HyperTwistTrainingSubsystemInternal::SerializeStruct(CommitPayload, CommitPayloadJson))
		{
			FHyperTwistReplayEvent CommitEvent;
			CommitEvent.EventType = EHyperTwistReplayEventType::RecognitionCommit;
			CommitEvent.PayloadJson = CommitPayloadJson;
			PendingRecognitionEvents.Add(CommitEvent);
		}
	}

	bool bMutatedReplay = false;
	for (const FHyperTwistReplayEvent& Event : PendingRecognitionEvents)
	{
		if (!HyperTwistTrainingSubsystemInternal::IsRecognitionReplayEventType(Event.EventType))
		{
			continue;
		}

		ActiveRunState.ReplayPacket = UHyperTwistReplayLibrary::AppendReplayEvent(
			ActiveRunState.ReplayPacket,
			Event
		);
		bMutatedReplay = true;
	}

	FString CloseError;
	if (!VisionClient->CloseVisionSession(SessionId, CloseError) && CloseError != TEXT("session-not-open"))
	{
		Result.NormalizationWarnings.AddUnique(CloseError);
	}

	ActiveRecognitionSessionState.bSessionOpen = false;
	ActiveRecognitionSessionState.bHasFinalizeResult = true;
	ActiveRecognitionSessionState.LastFinalizeResult = Result;
	ActiveRecognitionSessionState.ActiveSessionId.Reset();
	ActiveRecognitionSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	++ActiveRecognitionSessionState.FinalizedSessionCount;
	ActiveRecognitionSessionState.LastError =
		Result.NormalizationWarnings.Num() > 0 ? FString::Join(Result.NormalizationWarnings, TEXT(" | ")) : FString();
	ActiveRecognitionSessionState.ServiceHealth.LastError = ActiveRecognitionSessionState.LastError;

	if (bMutatedReplay)
	{
		SynchronizeRecognitionReplayMutation();
	}

	return Result;
}

bool UHyperTwistTrainingSubsystem::CloseActiveRecognitionSession(FString& OutError)
{
	OutError.Reset();

	if (!ActiveRecognitionSessionState.bSessionOpen || ActiveRecognitionSessionState.ActiveSessionId.IsEmpty())
	{
		RefreshRecognitionServiceHealth();
		return true;
	}

	IHyperTwistVisionClient* VisionClient = HyperTwistTrainingSubsystemInternal::ResolveVisionClient(
		ResolveRecognitionVisionClientObject()
	);
	if (VisionClient == nullptr)
	{
		OutError = TEXT("recognition-client-unavailable");
		ActiveRecognitionSessionState.LastError = OutError;
		RefreshRecognitionServiceHealth();
		return false;
	}

	const FString SessionId = ActiveRecognitionSessionState.ActiveSessionId;
	const bool bClosed = VisionClient->CloseVisionSession(SessionId, OutError);
	if (!bClosed && OutError != TEXT("session-not-open"))
	{
		ActiveRecognitionSessionState.LastError = OutError;
		RefreshRecognitionServiceHealth();
		return false;
	}

	ActiveRecognitionSessionState.bSessionOpen = false;
	ActiveRecognitionSessionState.ActiveSessionId.Reset();
	ActiveRecognitionSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveRecognitionSessionState.LastError.Reset();
	RefreshRecognitionServiceHealth();
	return true;
}

void UHyperTwistTrainingSubsystem::ClearActiveMethodDrillRun()
{
	ActiveMethodDrillRunState = FHyperTwistTrainingMethodDrillRunState();
	ActiveMethodDrillSummary = FHyperTwistTrainingMethodDrillSummary();
	ActiveMethodDrillDiagnosticPacket = FHyperTwistTrainingMethodDrillDiagnosticPacket();
	ActiveMethodDrillFollowUpTemplate = FHyperTwistTrainingSessionTemplate();
	bHasActiveMethodDrillRun = false;
}

UObject* UHyperTwistTrainingSubsystem::ResolveRecognitionVisionClientObject()
{
	LoadConfig();

	const bool bUseMockClient = RecognitionClientKind.Equals(TEXT("mock"), ESearchCase::IgnoreCase);
	const bool bNeedsNewClient = ActiveRecognitionVisionClientObject == nullptr
		|| (bUseMockClient && !ActiveRecognitionVisionClientObject->IsA<UHyperTwistMockVisionClient>())
		|| (!bUseMockClient && !ActiveRecognitionVisionClientObject->IsA<UHyperTwistHttpVisionClient>());
	if (bNeedsNewClient)
	{
		if (bUseMockClient)
		{
			ActiveRecognitionVisionClientObject = NewObject<UHyperTwistMockVisionClient>(this);
		}
		else
		{
			UHyperTwistHttpVisionClient* HttpVisionClient = NewObject<UHyperTwistHttpVisionClient>(this);
			HttpVisionClient->LoadConfig();
			ActiveRecognitionVisionClientObject = HttpVisionClient;
		}
	}

	return ActiveRecognitionVisionClientObject;
}

FHyperTwistVisionSessionConfig UHyperTwistTrainingSubsystem::BuildActiveRecognitionSessionConfig() const
{
	FHyperTwistVisionSessionConfig SessionConfig = ActiveRecognitionSessionState.SessionConfig;
	if (!HasActiveRun())
	{
		return SessionConfig;
	}

	const FHyperTwistPuzzleDefinitionRef& ReplayDefinition = ActiveRunState.ReplayPacket.PuzzleDefinition;
	const FHyperTwistTrainingCase* ActiveCase = ActiveRunState.CurrentSelection.IsStructurallyValid()
		? &ActiveRunState.CurrentSelection.TrainingCase
		: HyperTwistTrainingSubsystemInternal::FindFirstStructurallyValidCase(ActiveRunState.ActiveDeck);

	SessionConfig.SessionId = !ActiveRecognitionSessionState.ActiveSessionId.IsEmpty()
		? ActiveRecognitionSessionState.ActiveSessionId
		: HyperTwistTrainingSubsystemInternal::BuildRecognitionSessionId(
			ActiveRunState.Session,
			ActiveRecognitionSessionState.FinalizedSessionCount + 1
		);
	SessionConfig.PuzzleId = ReplayDefinition.IsStructurallyValid()
		? ReplayDefinition.PuzzleId
		: (ActiveCase != nullptr && !ActiveCase->PuzzleId.IsEmpty() ? ActiveCase->PuzzleId : TEXT("cube/3x3x3"));
	SessionConfig.ExpectedPuzzleFamily = ReplayDefinition.IsStructurallyValid()
		? ReplayDefinition.PuzzleFamily
		: HyperTwistTrainingSubsystemInternal::ResolvePuzzleFamilyFromPuzzleId(SessionConfig.PuzzleId);
	SessionConfig.NotationProfile = ReplayDefinition.IsStructurallyValid()
		? ReplayDefinition.NotationProfile
		: HyperTwistTrainingSubsystemInternal::ResolveNotationProfileFromPuzzleId(SessionConfig.PuzzleId);
	SessionConfig.CaptureMode = EHyperTwistVisionCaptureMode::LiveCamera;
	if (SessionConfig.FrameSize.X <= 0 || SessionConfig.FrameSize.Y <= 0)
	{
		SessionConfig.FrameSize = FIntPoint(1280, 720);
	}
	if (SessionConfig.MaxFrameRate <= 0)
	{
		SessionConfig.MaxFrameRate = 30;
	}

	return SessionConfig;
}

void UHyperTwistTrainingSubsystem::RefreshRecognitionServiceHealth()
{
	IHyperTwistVisionClient* VisionClient = HyperTwistTrainingSubsystemInternal::ResolveVisionClient(
		ResolveRecognitionVisionClientObject()
	);
	ActiveRecognitionSessionState.bUsingProviderBackedClient =
		ActiveRecognitionVisionClientObject != nullptr
		&& ActiveRecognitionVisionClientObject->IsA<UHyperTwistHttpVisionClient>();
	if (VisionClient == nullptr)
	{
		ActiveRecognitionSessionState.ServiceHealth = FHyperTwistVisionServiceHealth();
		ActiveRecognitionSessionState.ServiceHealth.ProviderLabel = ActiveRecognitionSessionState.bUsingProviderBackedClient
			? TEXT("local-http-sidecar")
			: TEXT("mock");
		ActiveRecognitionSessionState.ServiceHealth.ServiceEndpoint = ActiveRecognitionSessionState.bUsingProviderBackedClient
			? TEXT("http://127.0.0.1:8766")
			: TEXT("in-process://mock");
		ActiveRecognitionSessionState.ServiceHealth.bReady = false;
		ActiveRecognitionSessionState.ServiceHealth.LastError = TEXT("recognition-client-unavailable");
		return;
	}

	ActiveRecognitionSessionState.ServiceHealth = VisionClient->GetVisionServiceHealth();
}

void UHyperTwistTrainingSubsystem::AppendRecognitionReplayEvent(
	const EHyperTwistReplayEventType EventType,
	const FHyperTwistReplayRecognitionPayload& Payload,
	const int32 PreferredTimeMs
)
{
	if (!HasActiveRun())
	{
		return;
	}

	FString PayloadJson;
	if (!HyperTwistTrainingSubsystemInternal::SerializeStruct(Payload, PayloadJson))
	{
		return;
	}

	FHyperTwistReplayEvent ReplayEvent;
	ReplayEvent.EventType = EventType;
	ReplayEvent.PayloadJson = PayloadJson;

	const int32 LastTimeMs = ActiveRunState.ReplayPacket.Events.Num() > 0
		? ActiveRunState.ReplayPacket.Events.Last().TimeMs
		: 0;
	const int32 BaseTimeMs = PreferredTimeMs >= 0 ? PreferredTimeMs : LastTimeMs + 1;
	ReplayEvent.TimeMs = BaseTimeMs > LastTimeMs ? BaseTimeMs : LastTimeMs + 1;
	ActiveRunState.ReplayPacket = UHyperTwistReplayLibrary::AppendReplayEvent(
		ActiveRunState.ReplayPacket,
		ReplayEvent
	);
}

void UHyperTwistTrainingSubsystem::SynchronizeRecognitionReplayMutation()
{
	if (ActiveRunState.ReplayPacket.Events.Num() > 0)
	{
		ActiveRunState.LastReplayEvent = ActiveRunState.ReplayPacket.Events.Last();
	}
	else
	{
		ActiveRunState.LastReplayEvent = FHyperTwistReplayEvent();
	}

	RefreshSummary();
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
		TrainingRepositoryState,
		ActiveRunState
	);
	RefreshRepositoryViews();
}

void UHyperTwistTrainingSubsystem::ResetRecognitionSessionState()
{
	ActiveRecognitionSessionState = FHyperTwistTrainingRecognitionSessionState();
	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())
	{
		ActiveRunSummary = FHyperTwistTrainingSessionSummary();
		return;
	}

	ActiveRunSummary = UHyperTwistTrainingLibrary::DeriveTrainingSessionSummary(
		ActiveRunState.Session,
     ActiveRunState.Attempts,
		ActiveRunState.ImportedRuntimeSelectionState
	);
}

void UHyperTwistTrainingSubsystem::ResetActiveLiveTimerState()
{
	ActiveLiveTimerState = FHyperTwistTrainingLiveTimerState();
	ActiveLiveTimerStartedAtSeconds = 0.0;
	ActiveLiveTimerSolveStartedAtSeconds = 0.0;
	ActiveLiveTimerPausedAtSeconds = 0.0;
	ActiveLiveTimerStoredInspectionElapsedMs = 0;
	ActiveLiveTimerStoredSolveElapsedMs = 0;
}

void UHyperTwistTrainingSubsystem::RefreshActiveLiveTimerState()
{
	if (!HasActiveRun()
		|| !ActiveRunState.Session.IsStructurallyValid()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
	{
		ResetActiveLiveTimerState();
		return;
	}

	if (ActiveLiveTimerState.Phase == EHyperTwistTrainingLiveTimerPhase::Idle)
	{
		return;
	}

	if (ActiveLiveTimerState.TrainingSessionId != ActiveRunState.Session.TrainingSessionId
		|| ActiveLiveTimerState.CaseId != ActiveRunState.CurrentSelection.TrainingCase.CaseId)
	{
		ResetActiveLiveTimerState();
		return;
	}

	ActiveLiveTimerState = BuildActiveLiveTimerStateSnapshot(
		FPlatformTime::Seconds(),
		FDateTime::UtcNow().ToIso8601()
	);
}

FHyperTwistTrainingLiveTimerState UHyperTwistTrainingSubsystem::BuildActiveLiveTimerStateSnapshot(
	const double NowSeconds,
	const FString& NowUtc
) const
{
	FHyperTwistTrainingLiveTimerState Snapshot = ActiveLiveTimerState;
	if (!ActiveRunState.Session.IsStructurallyValid()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid()
		|| Snapshot.Phase == EHyperTwistTrainingLiveTimerPhase::Idle)
	{
		return Snapshot;
	}

	Snapshot.TrainingSessionId = ActiveRunState.Session.TrainingSessionId;
	Snapshot.UserId = ActiveRunState.Session.UserId;
	Snapshot.DeckId = !ActiveRunState.ActiveDeck.DeckId.IsEmpty()
		? ActiveRunState.ActiveDeck.DeckId
		: ActiveRunState.Session.DeckId;
	Snapshot.CaseId = ActiveRunState.CurrentSelection.TrainingCase.CaseId;
	Snapshot.TimingPolicy = UHyperTwistTrainingLibrary::NormalizeTimingPolicy(ActiveRunState.ActiveDeck.TimingPolicy);
	Snapshot.bHasInspectionWindow =
		Snapshot.TimingPolicy.bInspectionEnabled && Snapshot.TimingPolicy.InspectionDurationMs > 0;
	Snapshot.InspectionLimitMs = Snapshot.bHasInspectionWindow
		? FMath::Max(Snapshot.TimingPolicy.InspectionDurationMs, 0)
		: 0;
	Snapshot.bHideRunningTime = Snapshot.TimingPolicy.bHideRunningTime;
	Snapshot.LastUpdatedAtUtc = NowUtc;
	if (Snapshot.StartedAtUtc.IsEmpty())
	{
		Snapshot.StartedAtUtc = NowUtc;
	}

	int32 InspectionElapsedMs = FMath::Max(ActiveLiveTimerStoredInspectionElapsedMs, 0);
	int32 SolveElapsedMs = FMath::Max(ActiveLiveTimerStoredSolveElapsedMs, 0);
	switch (Snapshot.Phase)
	{
	case EHyperTwistTrainingLiveTimerPhase::Inspection:
		InspectionElapsedMs += FMath::Max(
			0,
			static_cast<int32>((NowSeconds - ActiveLiveTimerStartedAtSeconds) * 1000.0)
		);
		SolveElapsedMs = 0;
		Snapshot.DisplayedElapsedMs = InspectionElapsedMs;
		Snapshot.ResumePhase = EHyperTwistTrainingLiveTimerPhase::Inspection;
		break;
	case EHyperTwistTrainingLiveTimerPhase::Solving:
		SolveElapsedMs += FMath::Max(
			0,
			static_cast<int32>((NowSeconds - ActiveLiveTimerSolveStartedAtSeconds) * 1000.0)
		);
		Snapshot.DisplayedElapsedMs = SolveElapsedMs;
		Snapshot.ResumePhase = EHyperTwistTrainingLiveTimerPhase::Solving;
		break;
	case EHyperTwistTrainingLiveTimerPhase::Paused:
		Snapshot.DisplayedElapsedMs =
			Snapshot.ResumePhase == EHyperTwistTrainingLiveTimerPhase::Inspection
				? InspectionElapsedMs
				: SolveElapsedMs;
		break;
	case EHyperTwistTrainingLiveTimerPhase::Completed:
		Snapshot.DisplayedElapsedMs = SolveElapsedMs;
		break;
	default:
		InspectionElapsedMs = 0;
		SolveElapsedMs = 0;
		Snapshot.DisplayedElapsedMs = 0;
		break;
	}

	Snapshot.InspectionElapsedMs = InspectionElapsedMs;
	Snapshot.SolveElapsedMs = SolveElapsedMs;
	Snapshot.InspectionPenalty = HyperTwistTrainingSubsystemInternal::ComputeInspectionPenalty(
		InspectionElapsedMs,
		Snapshot.TimingPolicy
	);
	Snapshot.PendingPenalty = HyperTwistTrainingSubsystemInternal::CombinePenalties(
		Snapshot.InspectionPenalty,
		Snapshot.ManualPenalty
	);
	return Snapshot;
}

void UHyperTwistTrainingSubsystem::RefreshMethodDrillSummary()
{
	if (!ActiveMethodDrillRunState.IsStructurallyValid())
	{
		ActiveMethodDrillSummary = FHyperTwistTrainingMethodDrillSummary();
		ActiveMethodDrillDiagnosticPacket = FHyperTwistTrainingMethodDrillDiagnosticPacket();
		ActiveMethodDrillFollowUpTemplate = FHyperTwistTrainingSessionTemplate();
		return;
	}

	ActiveMethodDrillSummary = UHyperTwistTrainingLibrary::DeriveMethodDrillSummary(
		ActiveMethodDrillRunState
	);
	ActiveMethodDrillDiagnosticPacket = UHyperTwistTrainingLibrary::DeriveMethodDrillDiagnosticPacket(
		ActiveMethodDrillRunState
	);
	ActiveMethodDrillFollowUpTemplate = ActiveMethodDrillDiagnosticPacket.IsStructurallyValid()
		? HyperTwistTrainingSubsystemInternal::ApplyMethodDrillFollowUpMemoryBias(
			UHyperTwistTrainingRepositoryLibrary::BuildMethodDrillFollowUpTemplate(
				ActiveMethodDrillDiagnosticPacket,
				FString()
			),
			ActiveMethodDrillDiagnosticPacket,
			ActiveCoachMemorySnapshot
		)
		: FHyperTwistTrainingSessionTemplate();
}

void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
{
	ActiveRepositoryIntegrityReport = UHyperTwistTrainingRepositoryLibrary::DeriveRepositoryIntegrityReport(
		TrainingRepositoryState
	);
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RepairRepositoryState(TrainingRepositoryState);

	FString RepositoryViewUserId;
	FString RepositoryViewDeckId;
	FString RepositoryViewReferenceUtc;
	if (!TryResolveRepositoryViewContext(
			RepositoryViewUserId,
			RepositoryViewDeckId,
			RepositoryViewReferenceUtc))
	{
		ActiveDeckHistorySummary = FHyperTwistTrainingDeckHistorySummary();
		ActiveTimingTrendSummary = FHyperTwistTrainingTimingTrendSummary();
		ActivePersonalBestSummary = FHyperTwistTrainingPersonalBestSummary();
		ActiveDeckScopedStats = FHyperTwistTrainingDeckScopedStats();
		ActiveCurrentCaseScopedStats = FHyperTwistTrainingCaseScopedStats();
		ActiveLearnerDeckStateSummary = FHyperTwistTrainingLearnerDeckStateSummary();
		ActiveLearnerProfile = FHyperTwistTrainingLearnerProfile();
		ActiveCoachMemorySnapshot = FHyperTwistTrainingCoachMemorySnapshot();
		ActiveReplayReviewAnalytics = FHyperTwistReplayReviewAnalytics();
		ActiveRecognitionReplaySummary = FHyperTwistRecognitionReplaySummary();
		ActiveCoachSignals.Reset();
		ActiveCoachBrief = FHyperTwistCoachBrief();
		ActiveCoachActionPlan = FHyperTwistTrainingCoachActionPlan();
		ActiveCoachActionPlanSummary = FHyperTwistTrainingCoachActionPlanSummary();
		ActiveCoachActionPlanOutcomeSummary = FHyperTwistTrainingCoachActionPlanOutcomeSummary();
		ActiveCoachActionSequenceSummary = FHyperTwistTrainingCoachActionSequenceSummary();
		ActiveCoachActionClosureSummary = FHyperTwistTrainingCoachActionClosureSummary();
		ActiveCoachClosureMemorySummary = FHyperTwistTrainingCoachClosureMemorySummary();
		ActiveCoachRecommendationHistorySummary = FHyperTwistTrainingCoachRecommendationHistorySummary();
		ActiveCoachCarryForwardPolicySummary = FHyperTwistTrainingCoachCarryForwardPolicySummary();
		ActiveCoachArchivePolicySummary = FHyperTwistTrainingCoachArchivePolicySummary();
		ActiveCoachFollowUpBrief = FHyperTwistCoachBrief();
		ActiveCoachSessionQueueSummary = FHyperTwistCoachSessionQueueSummary();
		ActiveCoachSessionQueueState = FHyperTwistTrainingCoachSessionQueueState();
		ActiveCoachScheduleHorizonSummary = FHyperTwistCoachScheduleHorizonSummary();
		ActiveCoachSchedulePolicySummary = FHyperTwistCoachSchedulePolicySummary();
		ActiveCoachSessionQueueExecutionSummary = FHyperTwistTrainingCoachSessionQueueExecutionSummary();
		ActiveLearnerMethodSegments.Reset();
		ActiveLearnerPresets.Reset();
		ActiveTrainingSessionTemplates.Reset();
		ActiveCaseRecommendations.Reset();
		ActiveReviewPlanState = FHyperTwistTrainingReviewPlanState();
		ActiveReviewFlowStatus = FHyperTwistTrainingReviewFlowStatus();
		ActiveReviewProgramSummary = FHyperTwistTrainingReviewProgramSummary();
		return;
	}

	const bool bHasActiveRunContext = ActiveRunState.Session.IsStructurallyValid();

	ActiveLearnerProfile = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerProfile(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	ActiveCoachMemorySnapshot = UHyperTwistTrainingRepositoryLibrary::DeriveCoachMemorySnapshot(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	ActiveCoachClosureMemorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachClosureMemorySummary(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	ActiveCoachRecommendationHistorySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachRecommendationHistorySummary(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	ActiveCoachCarryForwardPolicySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachCarryForwardPolicySummary(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	ActiveCoachArchivePolicySummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachArchivePolicySummary(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	ActiveReviewProgramSummary = UHyperTwistTrainingRepositoryLibrary::DeriveReviewProgramSummary(
		TrainingRepositoryState,
		RepositoryViewUserId,
		RepositoryViewReferenceUtc
	);
	const bool bRepositoryHasPendingReviewPlan =
		!ActiveReviewProgramSummary.CurrentPlanId.IsEmpty()
		|| !ActiveReviewProgramSummary.NextPlanId.IsEmpty();
	if (!bHasActiveRunContext)
	{
		const FString RepositoryReviewPlanId = !ActiveReviewProgramSummary.CurrentPlanId.IsEmpty()
			? ActiveReviewProgramSummary.CurrentPlanId
			: ActiveReviewProgramSummary.NextPlanId;
		if (!RepositoryReviewPlanId.IsEmpty())
		{
			FHyperTwistTrainingReviewPlanState StoredReviewPlan;
			const bool bHasStoredReviewPlan = UHyperTwistTrainingRepositoryLibrary::TryGetReviewPlan(
				TrainingRepositoryState,
				RepositoryReviewPlanId,
				StoredReviewPlan
			);
			ActiveReviewPlanState = bHasStoredReviewPlan
				&& StoredReviewPlan.IsStructurallyValid()
				&& StoredReviewPlan.UserId == RepositoryViewUserId
				? StoredReviewPlan
				: FHyperTwistTrainingReviewPlanState();
		}
		else
		{
			ActiveReviewPlanState = FHyperTwistTrainingReviewPlanState();
		}
	}
	else if (
		(ActiveRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
			|| ActiveRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted)
		&& ActiveReviewPlanState.IsStructurallyValid()
		&& !bRepositoryHasPendingReviewPlan)
	{
		ActiveReviewPlanState = FHyperTwistTrainingReviewPlanState();
	}

	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,
			RepositoryViewUserId,
			ResolvedDeckId,
			CurrentCaseId,
			ActiveDeckScopedStats.ReferenceUtc
		)
		: FHyperTwistTrainingCaseScopedStats();
	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,
		RepositoryViewUserId,
		ResolvedReferenceUtc
	);
	ActiveLearnerPresets = UHyperTwistTrainingRepositoryLibrary::DeriveLearnerPresets(
		TrainingRepositoryState,
		RepositoryViewUserId,
		ResolvedReferenceUtc
	);
	ActiveTrainingSessionTemplates = BuildTrainingSessionTemplatesForUser(
		RepositoryViewUserId,
		ResolvedReferenceUtc
	);
	ActiveCaseRecommendations = RepositoryFocusDeck.IsStructurallyValid()
		? UHyperTwistTrainingRepositoryLibrary::ListCaseRecommendationsForDeck(
			TrainingRepositoryState,
			RepositoryFocusDeck,
			RepositoryViewUserId,
			ResolvedReferenceUtc,
			5
		)
		: TArray<FHyperTwistTrainingCaseRecommendation>();
	ActiveReviewFlowStatus = ActiveReviewPlanState.IsStructurallyValid()
		? UHyperTwistTrainingRepositoryLibrary::DeriveReviewFlowStatus(ActiveReviewPlanState)
		: FHyperTwistTrainingReviewFlowStatus();
	ActiveCoachActionPlanSummary = UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionPlanSummary(
		TrainingRepositoryState,
		RepositoryViewUserId,
		ResolvedReferenceUtc
	);
	if (!bHasActiveRunContext)
	{
		const bool bShouldRehydrateCompletedCoachActionPlanForCarryover =
			ActiveReviewProgramSummary.bHasCarryover
			&& !ActiveCoachActionPlanSummary.LastCompletedPlanId.IsEmpty();
		const FString RepositoryCoachActionPlanId =
			!ActiveCoachActionPlanSummary.CurrentPlanId.IsEmpty()
				? ActiveCoachActionPlanSummary.CurrentPlanId
				: (bShouldRehydrateCompletedCoachActionPlanForCarryover
					? ActiveCoachActionPlanSummary.LastCompletedPlanId
					: FString());
		if (!RepositoryCoachActionPlanId.IsEmpty())
		{
			FHyperTwistTrainingCoachActionPlan StoredCoachActionPlan;
			const bool bHasStoredCoachActionPlan =
				UHyperTwistTrainingRepositoryLibrary::TryGetCoachActionPlan(
					TrainingRepositoryState,
					RepositoryCoachActionPlanId,
					StoredCoachActionPlan
				);
			ActiveCoachActionPlan = bHasStoredCoachActionPlan
				&& StoredCoachActionPlan.IsStructurallyValid()
				&& StoredCoachActionPlan.UserId == RepositoryViewUserId
				? StoredCoachActionPlan
				: FHyperTwistTrainingCoachActionPlan();
		}
		else
		{
			ActiveCoachActionPlan = FHyperTwistTrainingCoachActionPlan();
		}
	}
	ActiveCoachActionPlanOutcomeSummary = ActiveCoachActionPlan.IsStructurallyValid()
		? UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionPlanOutcomeSummary(
			TrainingRepositoryState,
			ActiveCoachActionPlan,
			ResolvedReferenceUtc
		)
		: FHyperTwistTrainingCoachActionPlanOutcomeSummary();
	ActiveCoachActionSequenceSummary = ActiveCoachActionPlan.IsStructurallyValid()
		? UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionSequenceSummary(
			TrainingRepositoryState,
			ActiveCoachActionPlan,
			ResolvedReferenceUtc
		)
		: FHyperTwistTrainingCoachActionSequenceSummary();
	ActiveCoachActionClosureSummary = ActiveCoachActionPlan.IsStructurallyValid()
		? UHyperTwistTrainingRepositoryLibrary::DeriveCoachActionClosureSummary(
			TrainingRepositoryState,
			ActiveCoachActionPlan,
			ResolvedReferenceUtc
		)
		: FHyperTwistTrainingCoachActionClosureSummary();
	const bool bShouldCollapseRetainedIdleCoachActionability =
		!bHasActiveRunContext
		&& !RetainedRepositoryViewUserId.IsEmpty()
		&& !ActiveReviewProgramSummary.LastCompletedPlanId.IsEmpty()
		&& ActiveReviewProgramSummary.PendingPlanCount == 0
		&& !ActiveReviewProgramSummary.bHasCarryover
		&& !ActiveReviewPlanState.IsStructurallyValid()
		&& ActiveCoachActionClosureSummary.IsStructurallyValid()
		&& ActiveCoachActionClosureSummary.bSequenceClosed
		&& !ActiveCoachActionClosureSummary.bShouldSpawnFollowUp
		&& !ActiveCoachActionClosureSummary.bNeedsEscalation
		&& !ActiveCoachActionSequenceSummary.bHasOpenPlan;
	FHyperTwistTrainingSessionSummary RepositoryViewSessionSummary = bHasActiveRunContext
		? ActiveRunSummary
		: FHyperTwistTrainingSessionSummary();
	if (RepositoryViewSessionSummary.UserId.IsEmpty())
	{
		RepositoryViewSessionSummary.UserId = RepositoryViewUserId;
	}
	if (RepositoryViewSessionSummary.DeckId.IsEmpty())
	{
		RepositoryViewSessionSummary.DeckId = ResolvedDeckId;
	}
	ActiveCoachSignals = UHyperTwistTrainingCoachLibrary::DeriveCoachSignals(
		RepositoryViewSessionSummary,
		ActiveDeckScopedStats,
		ActiveLearnerDeckStateSummary,
		ActiveLearnerProfile,
		ActiveCoachMemorySnapshot,
		ActiveReviewProgramSummary,
		ActiveReplayReviewAnalytics,
		ActiveRecognitionReplaySummary
	);
	ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::DeriveCoachBrief(
		RepositoryViewSessionSummary,
		ActiveDeckScopedStats,
		ActiveLearnerDeckStateSummary,
		ActiveLearnerProfile,
		ActiveCoachMemorySnapshot,
		ActiveReviewProgramSummary,
		ActiveReplayReviewAnalytics,
		ActiveRecognitionReplaySummary
	);
	const FHyperTwistCoachSignal ClosureRecoveryHistorySignal =
		UHyperTwistTrainingCoachLibrary::DeriveClosureRecoveryHistorySignal(
			ActiveCoachActionClosureSummary,
			ActiveCoachMemorySnapshot,
			ActiveCoachBrief
		);
	if (!ClosureRecoveryHistorySignal.SignalId.IsEmpty())
	{
		ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithClosureRecoveryHistorySignal(
			ActiveCoachBrief,
			ClosureRecoveryHistorySignal
		);
		ActiveCoachSignals = ActiveCoachBrief.Signals;
	}
	const FHyperTwistCoachSignal LaunchBudgetHistorySignal =
		UHyperTwistTrainingCoachLibrary::DeriveLaunchBudgetHistorySignal(
			ActiveCoachMemorySnapshot,
			ActiveCoachBrief
		);
	if (!LaunchBudgetHistorySignal.SignalId.IsEmpty())
	{
		ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithLaunchBudgetHistorySignal(
			ActiveCoachBrief,
			LaunchBudgetHistorySignal
		);
		ActiveCoachSignals = ActiveCoachBrief.Signals;
	}
	const bool bShouldDeriveCoachFollowUpBrief = ActiveCoachActionPlanOutcomeSummary.IsStructurallyValid()
		&& !bShouldCollapseRetainedIdleCoachActionability
		&& (
			ActiveCoachActionClosureSummary.bShouldSpawnFollowUp
			|| (
				ActiveCoachMemorySnapshot.PreferredGuidanceLane == EHyperTwistTrainingCoachGuidanceLane::FollowUp
				&& ActiveCoachActionPlanOutcomeSummary.bNeedsFollowUpPlan
				&& !ActiveCoachActionSequenceSummary.bHasOpenPlan
				&& !ActiveCoachActionClosureSummary.bNeedsEscalation
			)
		);
	const auto RebuildActiveCoachQueueDerivedState = [&]()
	{
		if (bShouldCollapseRetainedIdleCoachActionability)
		{
			ActiveCoachFollowUpBrief = FHyperTwistCoachBrief();
			ActiveCoachSessionQueueSummary = FHyperTwistCoachSessionQueueSummary();
			const FString QueueStateUserId = !ActiveCoachSessionQueueState.UserId.IsEmpty()
				? ActiveCoachSessionQueueState.UserId
				: RepositoryViewUserId;
			if (!QueueStateUserId.IsEmpty())
			{
				TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveCoachSessionQueueState(
					TrainingRepositoryState,
					QueueStateUserId,
					HyperTwistTrainingSubsystemInternal::ActiveCoachSessionQueueId
				);
			}
			ActiveCoachSessionQueueState = FHyperTwistTrainingCoachSessionQueueState();
			ActiveCoachScheduleHorizonSummary = FHyperTwistCoachScheduleHorizonSummary();
			ActiveCoachSchedulePolicySummary = FHyperTwistCoachSchedulePolicySummary();
			ActiveCoachSessionQueueExecutionSummary = FHyperTwistTrainingCoachSessionQueueExecutionSummary();
			return;
		}
		ActiveCoachFollowUpBrief = bShouldDeriveCoachFollowUpBrief
			? UHyperTwistTrainingCoachLibrary::DeriveCoachFollowUpBrief(
				ActiveCoachBrief,
				ActiveCoachActionPlan,
				ActiveCoachActionPlanOutcomeSummary
			)
			: FHyperTwistCoachBrief();
		ActiveCoachSessionQueueSummary = UHyperTwistTrainingCoachLibrary::DeriveCoachSessionQueueSummary(
			ActiveCoachBrief,
			ActiveCoachFollowUpBrief,
			ActiveCoachMemorySnapshot,
			ActiveCoachArchivePolicySummary,
			ActiveReviewProgramSummary
		);
		if (ActiveCoachSessionQueueSummary.IsStructurallyValid())
		{
			FHyperTwistTrainingCoachSessionQueueState StoredQueueState;
			const bool bHasStoredQueueState = UHyperTwistTrainingRepositoryLibrary::TryGetCoachSessionQueueState(
				TrainingRepositoryState,
				ActiveCoachSessionQueueSummary.UserId,
				HyperTwistTrainingSubsystemInternal::ActiveCoachSessionQueueId,
				StoredQueueState
			);
			ActiveCoachSessionQueueState = bHasStoredQueueState
				? UHyperTwistTrainingRepositoryLibrary::ResolveCoachSessionQueueState(
					StoredQueueState,
					ActiveCoachSessionQueueSummary,
					ResolvedReferenceUtc
				)
				: UHyperTwistTrainingRepositoryLibrary::BuildCoachSessionQueueState(
					ActiveCoachSessionQueueSummary,
					HyperTwistTrainingSubsystemInternal::ActiveCoachSessionQueueId,
					ResolvedReferenceUtc
				);
			if (ActiveCoachSessionQueueState.IsStructurallyValid())
			{
				TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertCoachSessionQueueState(
					TrainingRepositoryState,
					ActiveCoachSessionQueueState
				);
			}
			ActiveCoachScheduleHorizonSummary = UHyperTwistTrainingCoachLibrary::DeriveCoachScheduleHorizonSummary(
				ActiveCoachSessionQueueState,
				ActiveCoachArchivePolicySummary,
				ResolvedReferenceUtc
			);
			ActiveCoachSchedulePolicySummary = UHyperTwistTrainingCoachLibrary::DeriveCoachSchedulePolicySummary(
				ActiveCoachSessionQueueState,
				ActiveCoachScheduleHorizonSummary,
				ActiveCoachActionClosureSummary,
				ActiveCoachMemorySnapshot,
				ActiveCoachArchivePolicySummary,
				ResolvedReferenceUtc
			);
			ActiveCoachSessionQueueExecutionSummary =
				UHyperTwistTrainingRepositoryLibrary::DeriveCoachSessionQueueExecutionSummary(
					TrainingRepositoryState,
					ActiveCoachSessionQueueState.UserId,
					ActiveCoachSessionQueueState.QueueId,
					ResolvedReferenceUtc
				);
		}
		else
		{
			const FString QueueStateUserId = !ActiveCoachSessionQueueState.UserId.IsEmpty()
				? ActiveCoachSessionQueueState.UserId
				: RepositoryViewUserId;
			if (!QueueStateUserId.IsEmpty())
			{
				TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveCoachSessionQueueState(
					TrainingRepositoryState,
					QueueStateUserId,
					HyperTwistTrainingSubsystemInternal::ActiveCoachSessionQueueId
				);
			}
			ActiveCoachSessionQueueState = FHyperTwistTrainingCoachSessionQueueState();
			ActiveCoachScheduleHorizonSummary = FHyperTwistCoachScheduleHorizonSummary();
			ActiveCoachSchedulePolicySummary = FHyperTwistCoachSchedulePolicySummary();
			ActiveCoachSessionQueueExecutionSummary = FHyperTwistTrainingCoachSessionQueueExecutionSummary();
		}
	};
	RebuildActiveCoachQueueDerivedState();
	const FHyperTwistCoachSignal QueueSuppressionSignal =
		UHyperTwistTrainingCoachLibrary::DeriveQueueSuppressionSignal(
			ActiveCoachSessionQueueSummary,
			ActiveCoachMemorySnapshot,
			ActiveCoachBrief,
			ActiveCoachFollowUpBrief
		);
	if (!QueueSuppressionSignal.SignalId.IsEmpty())
	{
		ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithQueueSuppressionSignal(
			ActiveCoachBrief,
			QueueSuppressionSignal
		);
		ActiveCoachSignals = ActiveCoachBrief.Signals;
		RebuildActiveCoachQueueDerivedState();
	}
	const FHyperTwistCoachSignal SchedulePolicyFeedbackSignal =
		UHyperTwistTrainingCoachLibrary::DeriveSchedulePolicyFeedbackSignal(
			ActiveCoachSchedulePolicySummary,
			ActiveCoachSessionQueueExecutionSummary,
			ActiveCoachMemorySnapshot,
			ActiveCoachBrief
		);
	if (!SchedulePolicyFeedbackSignal.SignalId.IsEmpty())
	{
		ActiveCoachBrief = UHyperTwistTrainingCoachLibrary::RefineCoachBriefWithSchedulePolicyFeedbackSignal(
			ActiveCoachBrief,
			SchedulePolicyFeedbackSignal
		);
		ActiveCoachSignals = ActiveCoachBrief.Signals;
		RebuildActiveCoachQueueDerivedState();
	}
}

TArray<FHyperTwistTrainingSessionTemplate> UHyperTwistTrainingSubsystem::BuildTrainingSessionTemplatesForUser(
	const FString& UserId,
	const FString& ReferenceUtc
) const
{
	if (UserId.IsEmpty())
	{
		return TArray<FHyperTwistTrainingSessionTemplate>();
	}

	const TArray<FHyperTwistTrainingSessionTemplate> DerivedTemplates =
		UHyperTwistTrainingRepositoryLibrary::DeriveTrainingSessionTemplates(
			TrainingRepositoryState,
			UserId,
			ReferenceUtc
		);
	return UHyperTwistTrainingRepositoryLibrary::MergeTrainingSessionTemplates(
		DerivedTemplates,
		TrainingRepositoryState,
		UserId
	);
}
