#include "HyperTwistTraining/HyperTwistTrainingSubsystem.h"

#include "HyperTwistRecognition/HyperTwistVisionClient.h"
#include "HyperTwistRecognition/HyperTwistSpeechClient.h"
#include "HyperTwistRecognition/HyperTwistRecognitionReplayLibrary.h"
#include "HyperTwistReplay/HyperTwistReplayLibrary.h"
#include "HyperTwistReplay/HyperTwistReplayReviewLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingClassicCubingLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingCoachLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingPersistenceLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingPublicationLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h"
#include "HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.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;
	}

	IHyperTwistSpeechClient* ResolveSpeechClient(UObject* Candidate)
	{
		return Candidate != nullptr && Candidate->GetClass()->ImplementsInterface(UHyperTwistSpeechClient::StaticClass())
			? Cast<IHyperTwistSpeechClient>(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 BuildSpeechSessionId(const FHyperTwistTrainingSession& Session, const int32 SessionOrdinal)
	{
		const int32 ResolvedOrdinal = FMath::Max(1, SessionOrdinal);
		return FString::Printf(TEXT("%s_speech_%02d"), *Session.TrainingSessionId, ResolvedOrdinal);
	}

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

	FString BuildSpeechUtteranceId(const FString& SessionId, const int32 UtteranceOrdinal)
	{
		return FString::Printf(TEXT("%s_utterance_%03d"), *SessionId, FMath::Max(1, UtteranceOrdinal));
	}

	bool IsQbrClassicCubeRoute(const FHyperTwistVisionSessionConfig& SessionConfig)
	{
		return SessionConfig.ExpectedPuzzleFamily == EHyperTwistPuzzleFamily::ClassicCube
			&& SessionConfig.PuzzleId == TEXT("cube/3x3x3");
	}

	const TArray<FString>& GetClassicRecognitionFaceOrder()
	{
		static const TArray<FString> FaceOrder = {
			TEXT("U"),
			TEXT("R"),
			TEXT("F"),
			TEXT("D"),
			TEXT("L"),
			TEXT("B")
		};
		return FaceOrder;
	}

	FString NormalizeRecognitionFaceId(const FString& FaceId)
	{
		FString Normalized = FaceId;
		Normalized = Normalized.TrimStartAndEnd();
		Normalized.ToUpperInline();
		return Normalized;
	}

	int32 GetClassicRecognitionFaceOrderIndex(const FString& FaceId)
	{
		const FString NormalizedFaceId = NormalizeRecognitionFaceId(FaceId);
		const TArray<FString>& FaceOrder = GetClassicRecognitionFaceOrder();
		for (int32 Index = 0; Index < FaceOrder.Num(); ++Index)
		{
			if (FaceOrder[Index] == NormalizedFaceId)
			{
				return Index;
			}
		}

		return MAX_int32;
	}

	float CalculateCommittedFaceConfidence(const FHyperTwistVisionCommittedFaceState& FaceState)
	{
		if (FaceState.LatestOrderedStickers.Num() <= 0)
		{
			return 0.0f;
		}

		float ConfidenceSum = 0.0f;
		for (const FHyperTwistVisionObservedSticker& Sticker : FaceState.LatestOrderedStickers)
		{
			ConfidenceSum += Sticker.Confidence;
		}

		return ConfidenceSum / static_cast<float>(FaceState.LatestOrderedStickers.Num());
	}

	void UpsertCorrectionTarget(
		TArray<FHyperTwistVisionCorrectionTarget>& Targets,
		const FHyperTwistVisionCorrectionTarget& Candidate
	)
	{
		const FString CandidateFaceId = NormalizeRecognitionFaceId(Candidate.FaceId);
		const int32 ExistingIndex = Targets.IndexOfByPredicate(
			[&CandidateFaceId](const FHyperTwistVisionCorrectionTarget& ExistingTarget)
			{
				return NormalizeRecognitionFaceId(ExistingTarget.FaceId) == CandidateFaceId;
			}
		);

		if (ExistingIndex == INDEX_NONE)
		{
			Targets.Add(Candidate);
			return;
		}

		if (Candidate.PriorityOrdinal < Targets[ExistingIndex].PriorityOrdinal)
		{
			Targets[ExistingIndex] = Candidate;
			return;
		}

		if (Candidate.PriorityOrdinal == Targets[ExistingIndex].PriorityOrdinal
			&& Candidate.bManualReviewPreferred
			&& !Targets[ExistingIndex].bManualReviewPreferred)
		{
			Targets[ExistingIndex].bManualReviewPreferred = true;
		}
	}

	const FHyperTwistVisionCommittedFaceState* FindCommittedFaceState(
		const FHyperTwistVisionReconstructionSession& Session,
		const FString& FaceId
	)
	{
		const FString NormalizedFaceId = NormalizeRecognitionFaceId(FaceId);
		return Session.CommittedFaces.FindByPredicate(
			[&NormalizedFaceId](const FHyperTwistVisionCommittedFaceState& Candidate)
			{
				return NormalizeRecognitionFaceId(Candidate.FaceId) == NormalizedFaceId;
			}
		);
	}

	const FHyperTwistVisionReconstructionStickerVote* FindStickerVote(
		const FHyperTwistVisionCommittedFaceState& FaceState,
		const int32 GridIndex
	)
	{
		return FaceState.StickerVotes.FindByPredicate(
			[GridIndex](const FHyperTwistVisionReconstructionStickerVote& Candidate)
			{
				return Candidate.GridIndex == GridIndex;
			}
		);
	}

	FString MakeStickerVoteKey(const FString& Notation, const FString& ColorId)
	{
		FString NormalizedColorId = ColorId;
		NormalizedColorId.ToLowerInline();
		return FString::Printf(
			TEXT("%s|%s"),
			*NormalizeRecognitionFaceId(Notation),
			*NormalizedColorId
		);
	}

	FString ResolveClassicFaceletToken(const FString& Notation, const FString& ColorId)
	{
		FString NormalizedColorId = ColorId;
		NormalizedColorId.ToLowerInline();
		if (NormalizedColorId == TEXT("white"))
		{
			return TEXT("W");
		}
		if (NormalizedColorId == TEXT("red"))
		{
			return TEXT("R");
		}
		if (NormalizedColorId == TEXT("green"))
		{
			return TEXT("G");
		}
		if (NormalizedColorId == TEXT("yellow"))
		{
			return TEXT("Y");
		}
		if (NormalizedColorId == TEXT("orange"))
		{
			return TEXT("O");
		}
		if (NormalizedColorId == TEXT("blue"))
		{
			return TEXT("B");
		}

		const FString NormalizedNotation = NormalizeRecognitionFaceId(Notation);
		if (NormalizedNotation == TEXT("U"))
		{
			return TEXT("W");
		}
		if (NormalizedNotation == TEXT("R"))
		{
			return TEXT("R");
		}
		if (NormalizedNotation == TEXT("F"))
		{
			return TEXT("G");
		}
		if (NormalizedNotation == TEXT("D"))
		{
			return TEXT("Y");
		}
		if (NormalizedNotation == TEXT("L"))
		{
			return TEXT("O");
		}
		if (NormalizedNotation == TEXT("B"))
		{
			return TEXT("B");
		}

		return FString();
	}

	bool IsUniformFaceletTokenArray(const TArray<FString>& FaceTokens)
	{
		if (FaceTokens.Num() != 9 || FaceTokens[0].IsEmpty())
		{
			return false;
		}

		for (int32 Index = 1; Index < FaceTokens.Num(); ++Index)
		{
			if (FaceTokens[Index] != FaceTokens[0])
			{
				return false;
			}
		}

		return true;
	}

	TArray<FString>* ResolveMutableClassicFaceTokens(
		FHyperTwistClassicFaceletSnapshotState& FaceletState,
		const FString& FaceId
	)
	{
		const FString NormalizedFaceId = NormalizeRecognitionFaceId(FaceId);
		if (NormalizedFaceId == TEXT("U"))
		{
			return &FaceletState.U;
		}
		if (NormalizedFaceId == TEXT("R"))
		{
			return &FaceletState.R;
		}
		if (NormalizedFaceId == TEXT("F"))
		{
			return &FaceletState.F;
		}
		if (NormalizedFaceId == TEXT("D"))
		{
			return &FaceletState.D;
		}
		if (NormalizedFaceId == TEXT("L"))
		{
			return &FaceletState.L;
		}
		if (NormalizedFaceId == TEXT("B"))
		{
			return &FaceletState.B;
		}

		return nullptr;
	}

	FHyperTwistVisionReconstructionSession BuildClassicRecognitionReconstructionSession(
		const FHyperTwistVisionSessionConfig& SessionConfig,
		const FString& SessionId,
		const FHyperTwistVisionReconstructionSession& ExistingSession,
		const FHyperTwistVisionFaceObservation& Observation,
		bool& OutWasRevision
	)
	{
		OutWasRevision = false;

		FHyperTwistVisionReconstructionSession Session = ExistingSession.IsStructurallyValid()
			? ExistingSession
			: FHyperTwistVisionReconstructionSession();
		Session.SessionId = SessionId;
		Session.PuzzleId = !SessionConfig.PuzzleId.IsEmpty() ? SessionConfig.PuzzleId : TEXT("cube/3x3x3");
		Session.ReconstructionProfile = TEXT("classic-face-vote-v1");
		Session.OrientationProfile = TEXT("classic-target-face-net-v1");
		Session.bUsesObservationVoting = true;

		const FString FaceId = NormalizeRecognitionFaceId(Observation.FaceId);
		const FHyperTwistVisionCommittedFaceState* PreviousFaceState = FindCommittedFaceState(Session, FaceId);
		OutWasRevision = PreviousFaceState != nullptr;

		FHyperTwistVisionCommittedFaceState FaceState;
		FaceState.FaceId = FaceId;
		FaceState.LatestObservationId = Observation.ObservationId;
		FaceState.OrderingProfile = Observation.OrderingProfile;
		FaceState.ObservationCount = PreviousFaceState != nullptr
			? PreviousFaceState->ObservationCount + 1
			: 1;
		FaceState.RevisionCount = PreviousFaceState != nullptr
			? PreviousFaceState->RevisionCount + 1
			: 0;
		FaceState.LatestOrderedStickers = Observation.OrderedStickers;

		for (const FHyperTwistVisionObservedSticker& Sticker : Observation.OrderedStickers)
		{
			TArray<FHyperTwistVisionStickerVoteTally> Tallies;
			if (PreviousFaceState != nullptr)
			{
				if (const FHyperTwistVisionReconstructionStickerVote* PreviousVote =
					FindStickerVote(*PreviousFaceState, Sticker.GridIndex))
				{
					Tallies = PreviousVote->Tallies;
				}
			}

			const FString StickerVoteKey = MakeStickerVoteKey(Sticker.Notation, Sticker.ColorId);
			bool bUpdatedExistingTally = false;
			for (FHyperTwistVisionStickerVoteTally& Tally : Tallies)
			{
				if (MakeStickerVoteKey(Tally.Notation, Tally.ColorId) == StickerVoteKey)
				{
					++Tally.VoteCount;
					bUpdatedExistingTally = true;
					break;
				}
			}

			if (!bUpdatedExistingTally)
			{
				FHyperTwistVisionStickerVoteTally Tally;
				Tally.Notation = NormalizeRecognitionFaceId(Sticker.Notation);
				Tally.ColorId = Sticker.ColorId;
				Tally.VoteCount = 1;
				Tallies.Add(Tally);
			}

			int32 WinningIndex = INDEX_NONE;
			int32 TotalVoteCount = 0;
			for (int32 TallyIndex = 0; TallyIndex < Tallies.Num(); ++TallyIndex)
			{
				const FHyperTwistVisionStickerVoteTally& Tally = Tallies[TallyIndex];
				TotalVoteCount += Tally.VoteCount;

				const bool bPreferThisTally = WinningIndex == INDEX_NONE
					|| Tally.VoteCount > Tallies[WinningIndex].VoteCount
					|| (Tally.VoteCount == Tallies[WinningIndex].VoteCount
						&& MakeStickerVoteKey(Tally.Notation, Tally.ColorId) == StickerVoteKey);
				if (bPreferThisTally)
				{
					WinningIndex = TallyIndex;
				}
			}

			if (WinningIndex == INDEX_NONE)
			{
				continue;
			}

			const FHyperTwistVisionStickerVoteTally& WinningTally = Tallies[WinningIndex];

			FHyperTwistVisionReconstructionStickerVote Vote;
			Vote.GridIndex = Sticker.GridIndex;
			Vote.GridRow = Sticker.GridRow;
			Vote.GridColumn = Sticker.GridColumn;
			Vote.WinningNotation = WinningTally.Notation;
			Vote.WinningColorId = WinningTally.ColorId;
			Vote.WinningVoteCount = WinningTally.VoteCount;
			Vote.TotalVoteCount = TotalVoteCount;
			Vote.bHadConflict = Tallies.Num() > 1;
			Vote.Tallies = Tallies;
			FaceState.bHasConflicts = FaceState.bHasConflicts || Vote.bHadConflict;
			FaceState.StickerVotes.Add(Vote);
		}

		const int32 ExistingFaceIndex = Session.CommittedFaces.IndexOfByPredicate(
			[&FaceId](const FHyperTwistVisionCommittedFaceState& Candidate)
			{
				return NormalizeRecognitionFaceId(Candidate.FaceId) == FaceId;
			}
		);
		if (ExistingFaceIndex == INDEX_NONE)
		{
			Session.CommittedFaces.Add(FaceState);
		}
		else
		{
			Session.CommittedFaces[ExistingFaceIndex] = FaceState;
		}

		Session.CommittedFaces.Sort(
			[](const FHyperTwistVisionCommittedFaceState& Left, const FHyperTwistVisionCommittedFaceState& Right)
			{
				return GetClassicRecognitionFaceOrderIndex(Left.FaceId)
					< GetClassicRecognitionFaceOrderIndex(Right.FaceId);
			}
		);

		Session.TotalCommittedFaceCount = Session.CommittedFaces.Num();
		Session.TotalRevisionCount = 0;
		float ConfidenceSum = 0.0f;
		int32 ConfidenceCount = 0;
		for (const FHyperTwistVisionCommittedFaceState& CommittedFace : Session.CommittedFaces)
		{
			Session.TotalRevisionCount += CommittedFace.RevisionCount;
			for (const FHyperTwistVisionObservedSticker& LatestSticker : CommittedFace.LatestOrderedStickers)
			{
				ConfidenceSum += LatestSticker.Confidence;
				++ConfidenceCount;
			}
		}
		Session.ConfidenceRollup = ConfidenceCount > 0
			? ConfidenceSum / static_cast<float>(ConfidenceCount)
			: 0.0f;
		Session.bHasStableOrientation = Session.TotalCommittedFaceCount > 0;
		Session.OrientationStateOrdinal = Session.TotalCommittedFaceCount;

		Session.MissingFaces.Reset();
		for (const FString& ExpectedFaceId : GetClassicRecognitionFaceOrder())
		{
			if (FindCommittedFaceState(Session, ExpectedFaceId) == nullptr)
			{
				Session.MissingFaces.Add(ExpectedFaceId);
			}
		}
		Session.bHasCompleteClassicCubeNet =
			Session.MissingFaces.Num() == 0
			&& Session.CommittedFaces.Num() == GetClassicRecognitionFaceOrder().Num();

		return Session;
	}

	bool TryBuildClassicFaceletSnapshotFromReconstruction(
		const FHyperTwistVisionReconstructionSession& Session,
		FHyperTwistClassicFaceletSnapshotState& OutFaceletState
	)
	{
		if (!Session.IsStructurallyValid() || !Session.bHasCompleteClassicCubeNet)
		{
			return false;
		}

		OutFaceletState = FHyperTwistClassicFaceletSnapshotState();
		OutFaceletState.bPreviewState = false;

		for (const FString& ExpectedFaceId : GetClassicRecognitionFaceOrder())
		{
			const FHyperTwistVisionCommittedFaceState* CommittedFace = FindCommittedFaceState(Session, ExpectedFaceId);
			TArray<FString>* FaceTokens = ResolveMutableClassicFaceTokens(OutFaceletState, ExpectedFaceId);
			if (CommittedFace == nullptr || FaceTokens == nullptr || CommittedFace->StickerVotes.Num() != 9)
			{
				return false;
			}

			FaceTokens->Reset();
			for (int32 GridIndex = 0; GridIndex < 9; ++GridIndex)
			{
				const FHyperTwistVisionReconstructionStickerVote* Vote = FindStickerVote(*CommittedFace, GridIndex);
				if (Vote == nullptr)
				{
					return false;
				}

				const FString Token = ResolveClassicFaceletToken(Vote->WinningNotation, Vote->WinningColorId);
				if (Token.IsEmpty())
				{
					return false;
				}

				FaceTokens->Add(Token);
			}
		}

		return OutFaceletState.U.Num() == 9
			&& OutFaceletState.R.Num() == 9
			&& OutFaceletState.F.Num() == 9
			&& OutFaceletState.D.Num() == 9
			&& OutFaceletState.L.Num() == 9
			&& OutFaceletState.B.Num() == 9;
	}

	bool TryBuildClassicRecognitionStateSnapshot(
		const FHyperTwistVisionSessionConfig& SessionConfig,
		const FHyperTwistVisionReconstructionSession& Session,
		FHyperTwistPuzzleState& OutState,
		FHyperTwistStateSnapshot& OutSnapshot
	)
	{
		FHyperTwistClassicFaceletSnapshotState FaceletState;
		if (!TryBuildClassicFaceletSnapshotFromReconstruction(Session, FaceletState))
		{
			return false;
		}

		FString PayloadJson;
		if (!SerializeStruct(FaceletState, PayloadJson))
		{
			return false;
		}

		FHyperTwistPuzzleDefinitionRef Definition;
		Definition.PuzzleId = !Session.PuzzleId.IsEmpty() ? Session.PuzzleId : TEXT("cube/3x3x3");
		Definition.PuzzleFamily = EHyperTwistPuzzleFamily::ClassicCube;
		Definition.Dimension = 3;
		Definition.DefinitionVersion = TEXT("2026.05");
		Definition.NotationProfile = !SessionConfig.NotationProfile.IsEmpty()
			? SessionConfig.NotationProfile
			: TEXT("classic-wca");
		Definition.SizeVector = {3, 3, 3};

		OutState = FHyperTwistPuzzleState();
		OutState.Definition = Definition;
		OutState.StateEncodingKind = EHyperTwistStateEncodingKind::Facelet;
		OutState.StateEncoding.EncodingProfile = FaceletState.EncodingProfile;
		OutState.StateEncoding.PayloadJson = PayloadJson;
		OutState.OrientationFrame.Reference = !Session.OrientationProfile.IsEmpty()
			? Session.OrientationProfile
			: TEXT("classic-target-face-net-v1");
		OutState.bIsSolved =
			IsUniformFaceletTokenArray(FaceletState.U)
			&& IsUniformFaceletTokenArray(FaceletState.R)
			&& IsUniformFaceletTokenArray(FaceletState.F)
			&& IsUniformFaceletTokenArray(FaceletState.D)
			&& IsUniformFaceletTokenArray(FaceletState.L)
			&& IsUniformFaceletTokenArray(FaceletState.B);
		OutState.Source = EHyperTwistStateSource::Recognition;
		OutState.CapturedAtUtc = FDateTime::UtcNow().ToIso8601();
		OutState.SourceConfidence = Session.ConfidenceRollup;
		OutState.SourceSessionId = Session.SessionId;
		OutState.Notes = TEXT("Phase 6R-C reconstruction session aggregate.");

		OutSnapshot = FHyperTwistStateSnapshot();
		OutSnapshot.SnapshotId = FString::Printf(TEXT("recognition_reconstruction_%s"), *Session.SessionId);
		OutSnapshot.State = OutState;
		OutSnapshot.DerivedHash = FString::Printf(
			TEXT("recognition-reconstruction-%s-%d-%d"),
			*Session.SessionId,
			Session.TotalCommittedFaceCount,
			Session.TotalRevisionCount
		);
		return OutSnapshot.IsStructurallyValid();
	}

	TArray<FHyperTwistVisionLocaleOption> BuildQbrSupportedVisionLocales()
	{
		auto MakeLocale = [](
			const TCHAR* LocaleCode,
			const TCHAR* DisplayLabel,
			const TCHAR* ScriptDirectionId,
			const TCHAR* TextFlowProfileId,
			const bool bRequiresComplexTextShaping,
			const TCHAR* FontReviewDescriptorId
		)
		{
			FHyperTwistVisionLocaleOption LocaleOption;
			LocaleOption.LocaleCode = LocaleCode;
			LocaleOption.DisplayLabel = DisplayLabel;
			LocaleOption.GuidanceModeId = TEXT("qbr-locale-guidance-routing-v1");
			LocaleOption.ScriptDirectionId = ScriptDirectionId;
			LocaleOption.TextFlowProfileId = TextFlowProfileId;
			LocaleOption.PresentationProfileId = TEXT("qbr-locale-presentation-v1");
			LocaleOption.FontReviewDescriptorId = FontReviewDescriptorId;
			LocaleOption.bRequiresComplexTextShaping = bRequiresComplexTextShaping;
			LocaleOption.bBundledFontAssetDeferred = true;
			return LocaleOption;
		};

		return {
			MakeLocale(TEXT("en"), TEXT("English"), TEXT("ltr"), TEXT("word-space-delimited"), false, TEXT("font-review/qbr/latin-core")),
			MakeLocale(TEXT("hu"), TEXT("Hungarian"), TEXT("ltr"), TEXT("word-space-delimited"), false, TEXT("font-review/qbr/latin-core")),
			MakeLocale(TEXT("de"), TEXT("Deutsch"), TEXT("ltr"), TEXT("word-space-delimited"), false, TEXT("font-review/qbr/latin-core")),
			MakeLocale(TEXT("fr"), TEXT("French"), TEXT("ltr"), TEXT("word-space-delimited"), false, TEXT("font-review/qbr/latin-core")),
			MakeLocale(TEXT("es"), TEXT("Spanish"), TEXT("ltr"), TEXT("word-space-delimited"), false, TEXT("font-review/qbr/latin-core")),
			MakeLocale(TEXT("nl"), TEXT("Nederlands"), TEXT("ltr"), TEXT("word-space-delimited"), false, TEXT("font-review/qbr/latin-core")),
			MakeLocale(TEXT("zh"), TEXT("简体中文"), TEXT("ltr"), TEXT("cjk-character-wrap"), false, TEXT("font-review/qbr/cjk-simplified")),
			MakeLocale(TEXT("zh-tw"), TEXT("台灣繁體中文"), TEXT("ltr"), TEXT("cjk-character-wrap"), false, TEXT("font-review/qbr/cjk-traditional")),
			MakeLocale(TEXT("ar"), TEXT("العربية"), TEXT("rtl"), TEXT("rtl-word-space-delimited"), true, TEXT("font-review/qbr/arabic-core")),
			MakeLocale(TEXT("fa"), TEXT("فارسی"), TEXT("rtl"), TEXT("rtl-word-space-delimited"), true, TEXT("font-review/qbr/persian-core"))
		};
	}

	FHyperTwistVisionFontReviewProfile BuildDefaultQbrFontReviewProfile(const FString& ProfileId)
	{
		FHyperTwistVisionFontReviewProfile Profile;
		Profile.FontReviewProfileId = ProfileId;
		Profile.ReviewPosture = TEXT("independent-font-license-review-required");
		Profile.ShippingPosture = TEXT("not-shipped-in-packet");
		Profile.ProvisioningPosture = TEXT("user-supplied-or-platform-provided");
		Profile.CodeLicenseBoundary = TEXT("code-license-reviewed-separately");
		Profile.bRequiresIndependentFontLicenseReview = true;
		Profile.bAllowsBundledFontRedistribution = false;
		Profile.bAllowsRuntimeFontDownloadInCurrentPacket = false;
		Profile.bRequiresComplexScriptCoverageVerification = true;
		return Profile;
	}

	TArray<FHyperTwistVisionFontReviewDescriptor> BuildQbrSupportedFontReviews()
	{
		auto MakeFontReview = [](
			const TCHAR* DescriptorId,
			const TCHAR* LocaleCode,
			const TCHAR* FontFamilyId,
			const TCHAR* ScriptCoverageProfileId,
			const TCHAR* ReviewDocumentPath
		)
		{
			FHyperTwistVisionFontReviewDescriptor Descriptor;
			Descriptor.FontReviewDescriptorId = DescriptorId;
			Descriptor.LocaleCode = LocaleCode;
			Descriptor.FontFamilyId = FontFamilyId;
			Descriptor.ScriptCoverageProfileId = ScriptCoverageProfileId;
			Descriptor.ReviewDocumentPath = ReviewDocumentPath;
			Descriptor.AcquisitionMode = TEXT("user-supplied-or-platform-provided");
			Descriptor.ReviewPosture = TEXT("per-font-license-review-required");
			Descriptor.bBundledWithCodeDistribution = false;
			Descriptor.bStandaloneDonorRenderingDeferred = true;
			return Descriptor;
		};

		return {
			MakeFontReview(TEXT("font-review/qbr/latin-core"), TEXT("en"), TEXT("ui-font/latin-core"), TEXT("latin-basic-word-space"), TEXT("locale/latin/font-license-review")),
			MakeFontReview(TEXT("font-review/qbr/cjk-simplified"), TEXT("zh"), TEXT("ui-font/cjk-simplified-core"), TEXT("cjk-character-wrap"), TEXT("locale/zh/font-license-review")),
			MakeFontReview(TEXT("font-review/qbr/cjk-traditional"), TEXT("zh-tw"), TEXT("ui-font/cjk-traditional-core"), TEXT("cjk-character-wrap"), TEXT("locale/zh-tw/font-license-review")),
			MakeFontReview(TEXT("font-review/qbr/arabic-core"), TEXT("ar"), TEXT("ui-font/arabic-core"), TEXT("rtl-arabic-complex-shaping"), TEXT("locale/ar/font-license-review")),
			MakeFontReview(TEXT("font-review/qbr/persian-core"), TEXT("fa"), TEXT("ui-font/persian-core"), TEXT("rtl-persian-complex-shaping"), TEXT("locale/fa/font-license-review"))
		};
	}

	FHyperTwistVisionLocaleOption ResolveVisionLocaleOption(
		const TArray<FHyperTwistVisionLocaleOption>& SupportedLocales,
		const FString& PreferredLocaleCode
	)
	{
		const FString NormalizedPreferredLocale = PreferredLocaleCode.TrimStartAndEnd().ToLower();
		for (const FHyperTwistVisionLocaleOption& LocaleOption : SupportedLocales)
		{
			if (LocaleOption.LocaleCode.Equals(NormalizedPreferredLocale, ESearchCase::IgnoreCase))
			{
				return LocaleOption;
			}
		}

		if (SupportedLocales.Num() > 0)
		{
			return SupportedLocales[0];
		}

		FHyperTwistVisionLocaleOption FallbackLocale;
		FallbackLocale.LocaleCode = TEXT("en");
		FallbackLocale.DisplayLabel = TEXT("English");
		FallbackLocale.GuidanceModeId = TEXT("qbr-locale-guidance-routing-v1");
		FallbackLocale.ScriptDirectionId = TEXT("ltr");
		FallbackLocale.TextFlowProfileId = TEXT("word-space-delimited");
		FallbackLocale.PresentationProfileId = TEXT("qbr-locale-presentation-v1");
		FallbackLocale.FontReviewDescriptorId = TEXT("font-review/qbr/latin-core");
		FallbackLocale.bRequiresComplexTextShaping = false;
		FallbackLocale.bBundledFontAssetDeferred = true;
		return FallbackLocale;
	}

	FHyperTwistVisionCalibrationProfile BuildDefaultClassicCubeCalibrationProfile(const FString& ProfileId)
	{
		FHyperTwistVisionCalibrationProfile Profile;
		Profile.ProfileId = ProfileId;
		Profile.PuzzleId = TEXT("cube/3x3x3");
		Profile.DominantColorMethod = TEXT("kmeans-1");
		Profile.ColorDistanceMethod = TEXT("ciede2000");
		Profile.bPersistsPerUserPalette = true;

		auto AddSwatch = [&Profile](
			const TCHAR* ColorId,
			const TCHAR* Notation,
			const FIntVector Bgr,
			const FVector Lab
		)
		{
			FHyperTwistVisionCalibrationSwatch Swatch;
			Swatch.ColorId = ColorId;
			Swatch.Notation = Notation;
			Swatch.ReferenceBgr = Bgr;
			Swatch.ReferenceLab = Lab;
			Profile.PaletteSwatches.Add(Swatch);
		};

		AddSwatch(TEXT("green"), TEXT("F"), FIntVector(0, 255, 0), FVector(87.737f, -86.185f, 83.181f));
		AddSwatch(TEXT("red"), TEXT("R"), FIntVector(0, 0, 255), FVector(53.233f, 80.109f, 67.220f));
		AddSwatch(TEXT("blue"), TEXT("B"), FIntVector(255, 0, 0), FVector(32.303f, 79.197f, -107.864f));
		AddSwatch(TEXT("orange"), TEXT("L"), FIntVector(0, 165, 255), FVector(74.200f, 23.900f, 78.900f));
		AddSwatch(TEXT("white"), TEXT("U"), FIntVector(255, 255, 255), FVector(100.000f, 0.000f, 0.000f));
		AddSwatch(TEXT("yellow"), TEXT("D"), FIntVector(0, 255, 255), FVector(97.139f, -21.554f, 94.478f));
		return Profile;
	}

	FHyperTwistVisionShellProfile BuildDefaultClassicCubeWebcamShellProfile(const FString& ProfileId)
	{
		FHyperTwistVisionShellProfile Profile;
		Profile.ShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("webcam-overlay");
		Profile.LocaleRoutingMode = TEXT("first-party-locale-cycle");
		Profile.DefaultLocaleCode = TEXT("en");
		Profile.FontReviewProfileId = TEXT("qbr-bundled-font-review-v1");
		Profile.FontReviewProfileDefinition = BuildDefaultQbrFontReviewProfile(Profile.FontReviewProfileId);
		Profile.SupportedFontReviews = BuildQbrSupportedFontReviews();
		Profile.SupportedLocales = BuildQbrSupportedVisionLocales();

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const int32 GridRows,
			const int32 GridColumns,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistVisionShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.GridRows = GridRows;
			Panel.GridColumns = GridColumns;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistVisionShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("preview-sticker-grid"), TEXT("sticker-grid"), TEXT("top-left"), 3, 3, true);
		AddPanel(TEXT("snapshot-sticker-grid"), TEXT("sticker-grid"), TEXT("left-stack-below-preview"), 3, 3, true);
		AddPanel(TEXT("scanned-side-counter"), TEXT("status-readout"), TEXT("bottom-left"), 0, 0, true);
		AddPanel(TEXT("classic-cube-net"), TEXT("cube-net"), TEXT("bottom-right"), 3, 4, true);
		AddPanel(TEXT("locale-indicator"), TEXT("status-readout"), TEXT("top-right"), 0, 0, true);
		AddPanel(TEXT("calibration-swatch-rail"), TEXT("calibration-rail"), TEXT("top-left-offset"), 6, 1, false);

		AddAction(TEXT("capture-snapshot"), TEXT("Space"), TEXT("snapshot-sticker-grid"));
		AddAction(TEXT("toggle-calibration"), TEXT("C"), TEXT("calibration-swatch-rail"));
		AddAction(TEXT("cycle-locale"), TEXT("L"), TEXT("locale-indicator"));
		AddAction(TEXT("close-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistVisionBrowserAssetReviewProfile BuildDefaultRubixCubeSolverBrowserAssetReviewProfile(
		const FString& ProfileId
	);

	TArray<FHyperTwistVisionBrowserAssetReviewDescriptor> BuildRubixCubeSolverBrowserAssetReviews();

	FHyperTwistVisionBrowserAssetReviewDescriptor ResolveBrowserAssetReviewDescriptor(
		const TArray<FHyperTwistVisionBrowserAssetReviewDescriptor>& SupportedReviews,
		const FString& PreferredDescriptorId
	);

	FHyperTwistVisionBrowserShellProfile BuildDefaultClassicCubeBrowserShellProfile(const FString& ProfileId)
	{
		FHyperTwistVisionBrowserShellProfile Profile;
		Profile.BrowserShellProfileId = ProfileId;
		Profile.TransportKind = TEXT("websocket");
		Profile.TransportEndpoint = TEXT("ws://localhost:8090/");
		Profile.CaptureIntervalMs = 100;
		Profile.bSupportsManualCubeEdit = true;
		Profile.bSupportsPlaybackStage = false;
		Profile.BrowserAssetReviewProfileId = TEXT("rubix-browser-asset-review-v1");
		Profile.BrowserAssetReviewProfileDefinition =
			BuildDefaultRubixCubeSolverBrowserAssetReviewProfile(Profile.BrowserAssetReviewProfileId);
		Profile.DefaultBrowserAssetReviewDescriptorId =
			TEXT("browser-asset-review/rubix-cube-solver/twistysim");
		Profile.SupportedBrowserAssetReviews = BuildRubixCubeSolverBrowserAssetReviews();
		Profile.OrderedStageIds = {
			TEXT("home-page"),
			TEXT("video-stream"),
			TEXT("cube-edit")
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistVisionShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddAction(TEXT("start-browser-capture"), TEXT("button:start-capture"), TEXT("home-page"));
		AddAction(TEXT("finish-browser-capture"), TEXT("button:finish-capture"), TEXT("video-stream"));
		AddAction(TEXT("apply-manual-corrections"), TEXT("button:apply-corrections"), TEXT("cube-edit"));
		AddAction(TEXT("restart-browser-session"), TEXT("button:restart-session"), TEXT("cube-edit"));
		return Profile;
	}

	FHyperTwistVisionBrowserAssetReviewProfile BuildDefaultRubixCubeSolverBrowserAssetReviewProfile(
		const FString& ProfileId
	)
	{
		FHyperTwistVisionBrowserAssetReviewProfile Profile;
		Profile.BrowserAssetReviewProfileId = ProfileId;
		Profile.ReviewPosture = TEXT("independent-browser-asset-license-review-required");
		Profile.ShippingPosture = TEXT("not-shipped-in-packet");
		Profile.ProvisioningPosture = TEXT("user-supplied-or-review-cleared-replacement");
		Profile.CodeLicenseBoundary = TEXT("code-license-reviewed-separately");
		Profile.bRequiresIndependentBrowserAssetReview = true;
		Profile.bAllowsBundledBrowserAssetRedistribution = false;
		Profile.bAllowsRuntimeBrowserAssetDownloadInCurrentPacket = false;
		Profile.bPlaybackVisualizationOwnershipDeferred = true;
		return Profile;
	}

	TArray<FHyperTwistVisionBrowserAssetReviewDescriptor> BuildRubixCubeSolverBrowserAssetReviews()
	{
		FHyperTwistVisionBrowserAssetReviewDescriptor Descriptor;
		Descriptor.BrowserAssetReviewDescriptorId =
			TEXT("browser-asset-review/rubix-cube-solver/twistysim");
		Descriptor.UpstreamComponentId =
			TEXT("vivaansinghvi07/rubix-cube-solver/frontend/lib/twistysim.min.js");
		Descriptor.AssetPathHint = TEXT("frontend/lib/twistysim.min.js");
		Descriptor.AssetKind = TEXT("browser-visualization-script");
		Descriptor.ReviewDocumentPath = TEXT("browser/twistysim/license-review");
		Descriptor.AcquisitionMode = TEXT("user-supplied-or-review-cleared-replacement");
		Descriptor.ReviewPosture = TEXT("per-asset-license-review-required");
		Descriptor.bBundledWithCodeDistribution = false;
		Descriptor.bPlaybackVisualizationDeferred = true;
		return {Descriptor};
	}

	FHyperTwistVisionBrowserAssetReviewDescriptor ResolveBrowserAssetReviewDescriptor(
		const TArray<FHyperTwistVisionBrowserAssetReviewDescriptor>& SupportedReviews,
		const FString& PreferredDescriptorId
	)
	{
		for (const FHyperTwistVisionBrowserAssetReviewDescriptor& Descriptor : SupportedReviews)
		{
			if (Descriptor.BrowserAssetReviewDescriptorId.Equals(
				PreferredDescriptorId,
				ESearchCase::IgnoreCase
			))
			{
				return Descriptor;
			}
		}

		if (SupportedReviews.Num() > 0)
		{
			return SupportedReviews[0];
		}

		FHyperTwistVisionBrowserAssetReviewDescriptor FallbackDescriptor;
		FallbackDescriptor.BrowserAssetReviewDescriptorId =
			TEXT("browser-asset-review/rubix-cube-solver/twistysim");
		FallbackDescriptor.UpstreamComponentId =
			TEXT("vivaansinghvi07/rubix-cube-solver/frontend/lib/twistysim.min.js");
		FallbackDescriptor.AssetPathHint = TEXT("frontend/lib/twistysim.min.js");
		FallbackDescriptor.AssetKind = TEXT("browser-visualization-script");
		FallbackDescriptor.ReviewDocumentPath = TEXT("browser/twistysim/license-review");
		FallbackDescriptor.AcquisitionMode = TEXT("user-supplied-or-review-cleared-replacement");
		FallbackDescriptor.ReviewPosture = TEXT("per-asset-license-review-required");
		FallbackDescriptor.bBundledWithCodeDistribution = false;
		FallbackDescriptor.bPlaybackVisualizationDeferred = true;
		return FallbackDescriptor;
	}

	FHyperTwistVisionSolveExplanationProfile BuildDefaultClassicCubeSolveExplanationProfile(
		const FString& ProfileId
	)
	{
		FHyperTwistVisionSolveExplanationProfile Profile;
		Profile.ExplanationProfileId = ProfileId;
		Profile.PuzzleId = TEXT("cube/3x3x3");
		Profile.RecommendationMode = TEXT("bounded-stage-ladder-v1");
		Profile.LocaleGuidanceMode = TEXT("qbr-locale-guidance-routing-v1");
		Profile.DefaultLocaleCode = TEXT("en");
		Profile.StartingOrientationHint = TEXT("front: green | top: white");
		Profile.FontReviewProfileId = TEXT("qbr-bundled-font-review-v1");
		Profile.FontReviewProfileDefinition = BuildDefaultQbrFontReviewProfile(Profile.FontReviewProfileId);
		Profile.SupportedFontReviews = BuildQbrSupportedFontReviews();
		Profile.bSupportsStageRecommendation = true;
		Profile.bSupportsStepNavigation = true;
		Profile.bSupportsPlaybackStage = false;
		Profile.SupportedLocales = BuildQbrSupportedVisionLocales();

		auto AddStep = [&Profile](
			const TCHAR* StepId,
			const TCHAR* StageId,
			const TCHAR* Title,
			const TCHAR* Description,
			const TCHAR* RecommendationLine,
			const int32 StageOrdinal
		)
		{
			FHyperTwistVisionSolveExplanationStep Step;
			Step.StepId = StepId;
			Step.StageId = StageId;
			Step.Title = Title;
			Step.Description = Description;
			Step.RecommendationLine = RecommendationLine;
			Step.StageOrdinal = StageOrdinal;
			Step.bPlaybackDeferred = true;
			Profile.Steps.Add(Step);
		};

		AddStep(
			TEXT("orient-centers-step"),
			TEXT("orient-centers"),
			TEXT("Orient Centers"),
			TEXT("Check the cube orientation and align the center reference before turning into the solve ladder."),
			TEXT("Confirm the edited net and lock the reference orientation before solve guidance begins."),
			0
		);
		AddStep(
			TEXT("solve-white-cross-step"),
			TEXT("solve-white-cross"),
			TEXT("Build First Cross"),
			TEXT("Assemble the opening cross with edge placement matched against the side colors."),
			TEXT("Start with a stable cross so later first-layer turns stay bounded and readable."),
			1
		);
		AddStep(
			TEXT("solve-first-layer-corners-step"),
			TEXT("solve-first-layer-corners"),
			TEXT("Place First-Layer Corners"),
			TEXT("Insert the matching corners to finish the first layer without disturbing the cross."),
			TEXT("Close the first layer before moving into the middle-band edge work."),
			2
		);
		AddStep(
			TEXT("solve-second-layer-edges-step"),
			TEXT("solve-second-layer-edges"),
			TEXT("Solve Middle-Layer Edges"),
			TEXT("Move the non-top edges into their middle-layer slots while preserving the solved first layer."),
			TEXT("Complete the middle layer so orientation-only work remains on the last layer."),
			3
		);
		AddStep(
			TEXT("solve-oll-edges-step"),
			TEXT("solve-oll-edges"),
			TEXT("Orient Last-Layer Edges"),
			TEXT("Turn the last-layer edges so the top-face color is established across the edge ring."),
			TEXT("Orient the last-layer edges before promoting corner orientation."),
			4
		);
		AddStep(
			TEXT("solve-oll-corners-step"),
			TEXT("solve-oll-corners"),
			TEXT("Orient Last-Layer Corners"),
			TEXT("Resolve the remaining top-face corner orientation while keeping the lower layers intact."),
			TEXT("Finish top-face orientation before any final permutation pass."),
			5
		);
		AddStep(
			TEXT("solve-pll-corners-step"),
			TEXT("solve-pll-corners"),
			TEXT("Permute Last-Layer Corners"),
			TEXT("Cycle the last-layer corners into their destination positions after orientation is complete."),
			TEXT("Place the last-layer corners first so the final edge permutation stays bounded."),
			6
		);
		AddStep(
			TEXT("solve-pll-edges-step"),
			TEXT("solve-pll-edges"),
			TEXT("Permute Last-Layer Edges"),
			TEXT("Finish the solve by cycling the last-layer edges into their final positions."),
			TEXT("Close with the last-layer edges; playback ownership remains deferred in this packet."),
			7
		);

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistVisionShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddAction(TEXT("start-solve-explanation"), TEXT("button:start-explanation"), TEXT("cube-edit"));
		AddAction(TEXT("step-solve-forward"), TEXT("button:next-step"), TEXT("solve-explanation-stage"));
		AddAction(TEXT("step-solve-backward"), TEXT("button:previous-step"), TEXT("solve-explanation-stage"));
		AddAction(TEXT("restart-solve-explanation"), TEXT("button:restart-explanation"), TEXT("solve-explanation-stage"));
		return Profile;
	}

	FHyperTwistVisionCorrectionProfile BuildDefaultClassicCubeCorrectionProfile(
		const FString& ProfileId
	)
	{
		FHyperTwistVisionCorrectionProfile Profile;
		Profile.CorrectionProfileId = ProfileId;
		Profile.PuzzleId = TEXT("cube/3x3x3");
		Profile.CorrectionMode = TEXT("bounded-multi-face-correction-v1");
		Profile.bSupportsTargetedRescan = true;
		Profile.bSupportsManualCubeEdit = true;
		Profile.bSupportsStageRestart = true;

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistVisionShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddAction(TEXT("capture-target-face"), TEXT("button:capture-target-face"), TEXT("video-stream"));
		AddAction(TEXT("rescan-target-face"), TEXT("button:rescan-target-face"), TEXT("video-stream"));
		AddAction(TEXT("apply-manual-corrections"), TEXT("button:apply-corrections"), TEXT("cube-edit"));
		AddAction(TEXT("restart-browser-session"), TEXT("button:restart-session"), TEXT("cube-edit"));
		return Profile;
	}

	bool IsCorrectionResolutionCommitKind(const FString& CommitKind)
	{
		return CommitKind.Equals(TEXT("correction-resolution"), ESearchCase::IgnoreCase)
			|| CommitKind.Equals(TEXT("resolve-correction"), ESearchCase::IgnoreCase);
	}

	const FHyperTwistVisionCorrectionTarget* FindCorrectionTarget(
		const FHyperTwistVisionCorrectionState& CorrectionState,
		const FString& FaceId
	)
	{
		const FString NormalizedFaceId = NormalizeRecognitionFaceId(FaceId);
		return CorrectionState.PendingTargets.FindByPredicate(
			[&NormalizedFaceId](const FHyperTwistVisionCorrectionTarget& Candidate)
			{
				return NormalizeRecognitionFaceId(Candidate.FaceId) == NormalizedFaceId;
			}
		);
	}

	FHyperTwistVisionFaceObservation BuildObservationFromCommittedFaceState(
		const FHyperTwistVisionCommittedFaceState& FaceState
	)
	{
		FHyperTwistVisionFaceObservation Observation;
		Observation.ObservationId = FaceState.LatestObservationId;
		Observation.FaceId = NormalizeRecognitionFaceId(FaceState.FaceId);
		Observation.OrderingProfile = FaceState.OrderingProfile;
		Observation.CandidateContourCount = FaceState.LatestOrderedStickers.Num();
		Observation.AcceptedContourCount = FaceState.LatestOrderedStickers.Num();
		Observation.bFoundStableThreeByThreeGrid = FaceState.LatestOrderedStickers.Num() == 9;
		Observation.bOrderingStable = FaceState.LatestOrderedStickers.Num() == 9;
		Observation.bCommitReady = true;
		Observation.OrderedStickers = FaceState.LatestOrderedStickers;
		return Observation;
	}

	bool HasAppliedResolutionForFace(
		const TArray<FHyperTwistVisionCorrectionResolution>& ResolutionLedger,
		const FHyperTwistVisionCommittedFaceState& FaceState
	)
	{
		const FString NormalizedFaceId = NormalizeRecognitionFaceId(FaceState.FaceId);
		return ResolutionLedger.ContainsByPredicate(
			[&NormalizedFaceId, &FaceState](const FHyperTwistVisionCorrectionResolution& Resolution)
			{
				return NormalizeRecognitionFaceId(Resolution.FaceId) == NormalizedFaceId
					&& Resolution.ObservationId == FaceState.LatestObservationId
					&& Resolution.RevisionCount == FaceState.RevisionCount;
			}
		);
	}

	void UpsertCorrectionResolution(
		TArray<FHyperTwistVisionCorrectionResolution>& ResolutionLedger,
		const FHyperTwistVisionCorrectionResolution& Candidate,
		bool& bAddedNewResolution
	)
	{
		bAddedNewResolution = false;

		const int32 ExistingIndex = ResolutionLedger.IndexOfByPredicate(
			[&Candidate](const FHyperTwistVisionCorrectionResolution& Existing)
			{
				return NormalizeRecognitionFaceId(Existing.FaceId)
						== NormalizeRecognitionFaceId(Candidate.FaceId)
					&& Existing.ObservationId == Candidate.ObservationId
					&& Existing.RevisionCount == Candidate.RevisionCount;
			}
		);
		if (ExistingIndex == INDEX_NONE)
		{
			ResolutionLedger.Add(Candidate);
			bAddedNewResolution = true;
			return;
		}

		ResolutionLedger[ExistingIndex] = Candidate;
	}

	FHyperTwistVisionCorrectionResolution BuildCorrectionResolution(
		const FHyperTwistVisionCommitRequest& Request,
		const FHyperTwistVisionCorrectionState& CorrectionState,
		const FHyperTwistVisionCommittedFaceState& FaceState
	)
	{
		const FString FaceId = NormalizeRecognitionFaceId(FaceState.FaceId);
		const FHyperTwistVisionCorrectionTarget* Target = FindCorrectionTarget(CorrectionState, FaceId);

		FHyperTwistVisionCorrectionResolution Resolution;
		Resolution.FaceId = FaceId;
		Resolution.ObservationId = FaceState.LatestObservationId;
		Resolution.RevisionCount = FaceState.RevisionCount;
		Resolution.RequestedActionId = !Request.RequestedActionId.IsEmpty()
			? Request.RequestedActionId
			: (Target != nullptr && !Target->RecommendedActionId.IsEmpty()
				? Target->RecommendedActionId
				: TEXT("apply-manual-corrections"));
		Resolution.ResolutionKind = !Request.ResolutionKind.IsEmpty()
			? Request.ResolutionKind
			: (FaceState.RevisionCount > 0
				? TEXT("manual-review-accepted")
				: TEXT("correction-review-accepted"));
		Resolution.ResolutionId = FString::Printf(
			TEXT("resolution-%s-%d-%s"),
			*FaceId,
			FaceState.RevisionCount,
			*Resolution.ResolutionKind
		);

		for (const FHyperTwistVisionCorrectionContradiction& Contradiction : CorrectionState.Contradictions)
		{
			if (NormalizeRecognitionFaceId(Contradiction.FaceId) == FaceId)
			{
				Resolution.ResolvedContradictionIds.Add(Contradiction.ContradictionId);
			}
		}

		Resolution.StatusLine = FString::Printf(
			TEXT("Accepted face %s after manual correction review."),
			*FaceId
		);
		Resolution.DetailLine = Resolution.ResolvedContradictionIds.Num() > 0
			? FString::Printf(
				TEXT("The current observation on face %s is now treated as reviewed in the bounded correction shell."),
				*FaceId
			)
			: FString::Printf(
				TEXT("The current bounded reading on face %s is accepted after manual review."),
				*FaceId
			);
		return Resolution;
	}

	FHyperTwistVisionShellState BuildClassicCubeWebcamShellState(
		const FHyperTwistVisionSessionConfig& SessionConfig,
		const FHyperTwistVisionReconstructionSession& ReconstructionSession,
		const FString& PreferredTargetFaceHint,
		const FString& PreferredCommittedFaceId
	)
	{
		FHyperTwistVisionShellState ShellState;
		const FHyperTwistVisionShellProfile ShellProfile =
			SessionConfig.ShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.ShellProfileDefinition
				: BuildDefaultClassicCubeWebcamShellProfile(
					!SessionConfig.ShellProfileId.IsEmpty()
						? SessionConfig.ShellProfileId
						: TEXT("classic-cube-webcam-shell-v1")
				);
		const FHyperTwistVisionLocaleOption ActiveLocaleOption = ResolveVisionLocaleOption(
			ShellProfile.SupportedLocales,
			ShellProfile.DefaultLocaleCode
		);
		ShellState.ShellProfileId = !SessionConfig.ShellProfileId.IsEmpty()
			? SessionConfig.ShellProfileId
			: TEXT("classic-cube-webcam-shell-v1");
		ShellState.LocaleCode = ActiveLocaleOption.LocaleCode;
		ShellState.LocaleDisplayLabel = ActiveLocaleOption.DisplayLabel;
		ShellState.ActiveLocaleScriptDirectionId = ActiveLocaleOption.ScriptDirectionId;
		ShellState.ActiveLocaleTextFlowProfileId = ActiveLocaleOption.TextFlowProfileId;
		ShellState.ActiveLocalePresentationProfileId = ActiveLocaleOption.PresentationProfileId;
		ShellState.FontReviewProfileId = ShellProfile.FontReviewProfileId;
		ShellState.ActiveFontReviewDescriptorId = ActiveLocaleOption.FontReviewDescriptorId;
		ShellState.bActiveLocaleRequiresComplexTextShaping =
			ActiveLocaleOption.bRequiresComplexTextShaping;
		ShellState.bBundledFontAssetDeferred = ActiveLocaleOption.bBundledFontAssetDeferred;
		ShellState.TargetSideCount = 6;
		ShellState.TargetFaceHint = !PreferredTargetFaceHint.IsEmpty()
			? NormalizeRecognitionFaceId(PreferredTargetFaceHint)
			: TEXT("F");
		ShellState.LastCommittedFaceId = !PreferredCommittedFaceId.IsEmpty()
			? NormalizeRecognitionFaceId(PreferredCommittedFaceId)
			: FString();
		ShellState.CalibrationProfileId = !SessionConfig.CalibrationProfile.IsEmpty()
			? SessionConfig.CalibrationProfile
			: SessionConfig.CalibrationProfileDefinition.ProfileId;
		for (const FHyperTwistVisionLocaleOption& LocaleOption : ShellProfile.SupportedLocales)
		{
			ShellState.AvailableLocaleCodes.AddUnique(LocaleOption.LocaleCode);
		}

		if (ReconstructionSession.IsStructurallyValid())
		{
			ShellState.ScannedSideCount = FMath::Max(0, ReconstructionSession.TotalCommittedFaceCount);
			for (const FHyperTwistVisionCommittedFaceState& FaceState : ReconstructionSession.CommittedFaces)
			{
				const FString FaceId = NormalizeRecognitionFaceId(FaceState.FaceId);
				if (!FaceId.IsEmpty())
				{
					ShellState.CapturedFaceIds.Add(FaceId);
				}
			}

			if ((PreferredTargetFaceHint.IsEmpty() || ShellState.TargetFaceHint.IsEmpty())
				&& ReconstructionSession.MissingFaces.Num() > 0)
			{
				ShellState.TargetFaceHint = NormalizeRecognitionFaceId(ReconstructionSession.MissingFaces[0]);
			}

			if (ShellState.LastCommittedFaceId.IsEmpty() && ReconstructionSession.CommittedFaces.Num() > 0)
			{
				ShellState.LastCommittedFaceId =
					NormalizeRecognitionFaceId(ReconstructionSession.CommittedFaces.Last().FaceId);
			}
		}

		return ShellState;
	}

	FHyperTwistVisionBrowserShellState BuildClassicCubeBrowserShellState(
		const FHyperTwistVisionSessionConfig& SessionConfig,
		const FHyperTwistVisionReconstructionSession& ReconstructionSession,
		const FHyperTwistVisionFaceObservation& ObservedFace
	)
	{
		FHyperTwistVisionBrowserShellState BrowserShellState;
		const FHyperTwistVisionBrowserShellProfile BrowserShellProfile =
			SessionConfig.BrowserShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.BrowserShellProfileDefinition
				: BuildDefaultClassicCubeBrowserShellProfile(
					!SessionConfig.BrowserShellProfileId.IsEmpty()
						? SessionConfig.BrowserShellProfileId
						: TEXT("classic-cube-browser-shell-v1")
				);

		BrowserShellState.BrowserShellProfileId = BrowserShellProfile.BrowserShellProfileId;
		BrowserShellState.TransportKind = BrowserShellProfile.TransportKind;
		BrowserShellState.TransportEndpoint = BrowserShellProfile.TransportEndpoint;
		BrowserShellState.CaptureIntervalMs = BrowserShellProfile.CaptureIntervalMs;
		BrowserShellState.BrowserAssetReviewProfileId = BrowserShellProfile.BrowserAssetReviewProfileId;
		BrowserShellState.CubeDimension = 3;
		BrowserShellState.CommittedFaceCount = ReconstructionSession.IsStructurallyValid()
			? FMath::Max(0, ReconstructionSession.TotalCommittedFaceCount)
			: 0;
		BrowserShellState.ExpectedFaceCount = 6;
		BrowserShellState.TargetFaceHint = !ObservedFace.FaceId.IsEmpty()
			? NormalizeRecognitionFaceId(ObservedFace.FaceId)
			: TEXT("F");
		const FHyperTwistVisionBrowserAssetReviewDescriptor ActiveAssetReview =
			ResolveBrowserAssetReviewDescriptor(
				BrowserShellProfile.SupportedBrowserAssetReviews,
				BrowserShellProfile.DefaultBrowserAssetReviewDescriptorId
			);
		BrowserShellState.ActiveBrowserAssetReviewDescriptorId =
			ActiveAssetReview.BrowserAssetReviewDescriptorId;
		BrowserShellState.bBundledBrowserAssetDeferred =
			!ActiveAssetReview.bBundledWithCodeDistribution;
		BrowserShellState.bTransportRouteReady = true;
		BrowserShellState.bPlaybackDeferred = !BrowserShellProfile.bSupportsPlaybackStage;
		BrowserShellState.bSnapshotReady = ObservedFace.IsStructurallyValid() && ObservedFace.bCommitReady;

		if (ReconstructionSession.bHasCompleteClassicCubeNet)
		{
			BrowserShellState.ActiveStageId = TEXT("cube-edit");
			BrowserShellState.bVideoStreamVisible = false;
			BrowserShellState.bManualCubeEditVisible = true;
			BrowserShellState.bManualCubeEditReady = true;
		}
		else
		{
			BrowserShellState.ActiveStageId = TEXT("video-stream");
			BrowserShellState.bVideoStreamVisible = true;
			BrowserShellState.bManualCubeEditVisible = false;
			BrowserShellState.bManualCubeEditReady = false;
		}

		if (BrowserShellState.TargetFaceHint.IsEmpty() && ReconstructionSession.MissingFaces.Num() > 0)
		{
			BrowserShellState.TargetFaceHint =
				NormalizeRecognitionFaceId(ReconstructionSession.MissingFaces[0]);
		}

		return BrowserShellState;
	}

	FHyperTwistSpeechMicrophoneShellState BuildCoachCommandMicrophoneShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState,
		const bool bSessionOpen
	);

	FHyperTwistSpeechDevicePermissionWorkflowState BuildSpeechDevicePermissionWorkflowState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechNativeCaptureRouteWorkflowState BuildSpeechNativeCaptureRouteWorkflowState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechNativeCaptureRouteShellState BuildSpeechNativeCaptureRouteShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechExternalDictationShellState BuildSpeechExternalDictationShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechUsageCostDashboardShellState BuildSpeechUsageCostDashboardShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechUsageCostHistoryExportShellState BuildSpeechUsageCostHistoryExportShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechProviderReceiptReviewShellState BuildSpeechProviderReceiptReviewShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechProviderBillingSettlementShellState BuildSpeechProviderBillingSettlementShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechProviderSettlementExceptionShellState
	BuildSpeechProviderSettlementExceptionShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	);

	FHyperTwistSpeechMicrophoneShellProfile BuildDefaultCoachCommandMicrophoneShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechMicrophoneShellProfile Profile;
		Profile.MicrophoneShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("microphone-overlay");
		Profile.CaptureMode = TEXT("vad-gated-short-command");
		Profile.StepWindowMs = 3000;
		Profile.CaptureWindowMs = 10000;
		Profile.KeepWindowMs = 200;
		Profile.AudioContextTokens = 0;
		Profile.VadThreshold = 0.6f;
		Profile.HighPassFrequencyHz = 100.0f;
		Profile.bKeepContextBetweenChunks = false;
		Profile.bSupportsStreamingPreview = true;
		Profile.bSupportsManualCommit = true;
		Profile.PermissionContractId = TEXT("device-permission-shell-v1");
		Profile.CaptureRouteContractId = TEXT("capture-route-readiness-shell-v1");
		Profile.PermissionRequestActionId = TEXT("request-microphone-permission");
		Profile.CaptureRouteRetryActionId = TEXT("retry-capture-route");
		Profile.bSupportsPermissionRequest = true;
		Profile.bSupportsCaptureRouteRetry = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("microphone-status-readout"), TEXT("status-readout"), TEXT("top-left"), true);
		AddPanel(TEXT("vad-meter"), TEXT("level-meter"), TEXT("left-stack-below-status"), true);
		AddPanel(TEXT("transcript-preview"), TEXT("transcript-preview"), TEXT("bottom-left"), true);
		AddPanel(TEXT("command-hints"), TEXT("command-hints"), TEXT("top-right"), true);

		AddAction(TEXT("pause-microphone-capture"), TEXT("P"), TEXT("microphone-status-readout"));
		AddAction(TEXT("resume-microphone-capture"), TEXT("R"), TEXT("microphone-status-readout"));
		AddAction(TEXT("commit-transcript"), TEXT("Enter"), TEXT("transcript-preview"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechDevicePermissionWorkflowProfile
	BuildDefaultSpeechDevicePermissionWorkflowProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechDevicePermissionWorkflowProfile Profile;
		Profile.DevicePermissionWorkflowProfileId = ProfileId;
		Profile.WorkflowKind = TEXT("operator-device-permission-workflow");
		Profile.PermissionContractId = TEXT("device-permission-workflow-v1");
		Profile.SettingsHandoffContractId = TEXT("device-permission-settings-handoff-v1");
		Profile.PermissionRecheckContractId = TEXT("device-permission-recheck-v1");
		Profile.PermissionRequestActionId = TEXT("request-microphone-permission");
		Profile.OpenSettingsActionId = TEXT("open-microphone-privacy-settings");
		Profile.PermissionRecheckActionId = TEXT("recheck-microphone-permission");
		Profile.bSupportsPermissionRequest = true;
		Profile.bSupportsSettingsHandoff = true;
		Profile.bSupportsPermissionRecheck = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("permission-workflow-summary-card"), TEXT("permission-workflow-summary-card"), TEXT("top-left"), true);
		AddPanel(TEXT("permission-settings-handoff-card"), TEXT("permission-settings-handoff-card"), TEXT("left-stack-below-summary"), true);
		AddPanel(TEXT("permission-recheck-card"), TEXT("permission-recheck-card"), TEXT("right-stack-aligned-summary"), true);

		AddAction(TEXT("request-microphone-permission"), TEXT("P"), TEXT("permission-workflow-summary-card"));
		AddAction(TEXT("open-microphone-privacy-settings"), TEXT("S"), TEXT("permission-settings-handoff-card"));
		AddAction(TEXT("recheck-microphone-permission"), TEXT("R"), TEXT("permission-recheck-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechNativeCaptureRouteWorkflowProfile
	BuildDefaultSpeechNativeCaptureRouteWorkflowProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechNativeCaptureRouteWorkflowProfile Profile;
		Profile.NativeCaptureRouteWorkflowProfileId = ProfileId;
		Profile.WorkflowKind = TEXT("first-party-native-capture-route-workflow");
		Profile.OwnershipContractId = TEXT("native-capture-route-ownership-v1");
		Profile.PreparationContractId = TEXT("native-capture-route-preparation-v1");
		Profile.SessionReopenContractId = TEXT("native-capture-route-session-reopen-v1");
		Profile.RouteInspectActionId = TEXT("inspect-native-capture-route");
		Profile.PreparationRetryActionId = TEXT("retry-capture-route");
		Profile.SessionReopenActionId = TEXT("reopen-speech-session");
		Profile.PermissionDependencyActionId = TEXT("resolve-device-permission-workflow");
		Profile.bSupportsRouteInspect = true;
		Profile.bSupportsPreparationRetry = true;
		Profile.bSupportsSessionReopen = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("capture-route-ownership-summary-card"), TEXT("capture-route-ownership-summary-card"), TEXT("top-left"), true);
		AddPanel(TEXT("capture-route-preparation-card"), TEXT("capture-route-preparation-card"), TEXT("left-stack-below-summary"), true);
		AddPanel(TEXT("capture-route-session-reopen-card"), TEXT("capture-route-session-reopen-card"), TEXT("right-stack-aligned-summary"), true);

		AddAction(TEXT("inspect-native-capture-route"), TEXT("I"), TEXT("capture-route-ownership-summary-card"));
		AddAction(TEXT("retry-capture-route"), TEXT("R"), TEXT("capture-route-preparation-card"));
		AddAction(TEXT("reopen-speech-session"), TEXT("O"), TEXT("capture-route-session-reopen-card"));
		AddAction(TEXT("resolve-device-permission-workflow"), TEXT("P"), TEXT("capture-route-ownership-summary-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechNativeCaptureRouteShellProfile
	BuildDefaultSpeechNativeCaptureRouteShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechNativeCaptureRouteShellProfile Profile;
		Profile.NativeCaptureRouteShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-native-capture-route-workflow");
		Profile.OwnershipSummarySurfaceMode = TEXT("capture-route-ownership-summary-card");
		Profile.PreparationSurfaceMode = TEXT("capture-route-preparation-card");
		Profile.SessionReopenSurfaceMode = TEXT("capture-route-session-reopen-card");
		Profile.RouteInspectActionId = TEXT("inspect-native-capture-route");
		Profile.PreparationRetryActionId = TEXT("retry-capture-route");
		Profile.SessionReopenActionId = TEXT("reopen-speech-session");
		Profile.PermissionDependencyActionId = TEXT("resolve-device-permission-workflow");
		Profile.bSupportsOwnershipSummaryCard = true;
		Profile.bSupportsPreparationCard = true;
		Profile.bSupportsSessionReopenCard = true;
		Profile.bSupportsPermissionDependencyBanner = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("capture-route-ownership-summary-card"), TEXT("capture-route-ownership-summary-card"), TEXT("top-left"), true);
		AddPanel(TEXT("capture-route-preparation-card"), TEXT("capture-route-preparation-card"), TEXT("left-stack-below-summary"), true);
		AddPanel(TEXT("capture-route-session-reopen-card"), TEXT("capture-route-session-reopen-card"), TEXT("right-stack-aligned-summary"), true);

		AddAction(TEXT("inspect-native-capture-route"), TEXT("I"), TEXT("capture-route-ownership-summary-card"));
		AddAction(TEXT("retry-capture-route"), TEXT("R"), TEXT("capture-route-preparation-card"));
		AddAction(TEXT("reopen-speech-session"), TEXT("O"), TEXT("capture-route-session-reopen-card"));
		AddAction(TEXT("resolve-device-permission-workflow"), TEXT("P"), TEXT("capture-route-ownership-summary-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechExternalDictationShellProfile
	BuildDefaultSpeechExternalDictationShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechExternalDictationShellProfile Profile;
		Profile.ExternalDictationShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-external-dictation-shell");
		Profile.TranscriptHistorySurfaceMode = TEXT("rolling-transcript-history");
		Profile.OutputRoutingSurfaceMode = TEXT("clipboard-typing-script-routing");
		Profile.PostProcessOverlaySurfaceMode = TEXT("transcript-post-process-overlay");
		Profile.GlobalHotkeySurfaceMode = TEXT("platform-scoped-dictation-shortcut-lifecycle");
		Profile.InputDeviceSurfaceMode = TEXT("selected-input-device-cycle");
		Profile.OutputDeviceSurfaceMode = TEXT("selected-output-device-cycle");
		Profile.MuteSurfaceMode = TEXT("mute-while-recording-toggle");
		Profile.MicrophoneModeSurfaceMode = TEXT("lazy-close-and-always-on-mode");
		Profile.LocalModelCatalogSurfaceMode = TEXT("local-model-catalog-review");
		Profile.ModelIntegritySurfaceMode = TEXT("payload-integrity-review");
		Profile.ModelUnloadSurfaceMode = TEXT("sidecar-model-unload-policy");
		Profile.StartCaptureActionId = TEXT("start-external-dictation-capture");
		Profile.CancelCaptureActionId = TEXT("cancel-external-dictation-capture");
		Profile.CycleOutputRouteActionId = TEXT("cycle-external-dictation-output-route");
		Profile.CopyTranscriptActionId = TEXT("copy-latest-dictation-transcript");
		Profile.PasteTranscriptActionId = TEXT("paste-latest-dictation-transcript");
		Profile.ScriptDispatchActionId = TEXT("dispatch-dictation-script-output");
		Profile.TogglePostProcessOverlayActionId =
			TEXT("toggle-dictation-post-process-overlay");
		Profile.ReopenSpeechSessionActionId = TEXT("reopen-speech-session");
		Profile.RouteInspectActionId = TEXT("inspect-provider-route");
		Profile.InspectGlobalHotkeyActionId = TEXT("inspect-dictation-global-hotkey");
		Profile.CycleInputDeviceActionId = TEXT("cycle-dictation-input-device");
		Profile.CycleOutputDeviceActionId = TEXT("cycle-dictation-output-device");
		Profile.ToggleMuteWhileRecordingActionId =
			TEXT("toggle-dictation-mute-while-recording");
		Profile.ToggleMicrophoneModeActionId = TEXT("toggle-dictation-microphone-mode");
		Profile.InspectLocalModelCatalogActionId = TEXT("inspect-local-model-catalog");
		Profile.ReviewLocalModelIntegrityActionId = TEXT("review-local-model-integrity");
		Profile.ReviewLocalModelUnloadPolicyActionId =
			TEXT("review-local-model-unload-policy");
		Profile.PrimaryHotkeyBindingLabel = TEXT("ctrl+space");
		Profile.PostProcessHotkeyBindingLabel = TEXT("ctrl+shift+space");
		Profile.RetainedHistoryEntryLimit = 12;
		Profile.bSupportsTranscriptHistoryTimeline = true;
		Profile.bSupportsClipboardRouting = true;
		Profile.bSupportsTypingRouting = true;
		Profile.bSupportsScriptDispatchRouting = true;
		Profile.bSupportsTranscriptPostProcessOverlay = true;
		Profile.bSupportsGlobalHotkeyLifecycle = true;
		Profile.bSupportsInputDeviceSelection = true;
		Profile.bSupportsOutputDeviceSelection = true;
		Profile.bSupportsMuteWhileRecordingToggle = true;
		Profile.bSupportsAlwaysOnMicrophoneMode = true;
		Profile.bSupportsClamshellInputFallback = true;
		Profile.bSupportsLazyCloseLifecycle = true;
		Profile.bSupportsLocalModelCatalogReview = true;
		Profile.bSupportsModelIntegrityReview = true;
		Profile.bSupportsModelUnloadPolicyReview = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("dictation-history-card"), TEXT("dictation-history-card"), TEXT("top-left"), true);
		AddPanel(TEXT("dictation-output-routing-card"), TEXT("dictation-output-routing-card"), TEXT("top-right"), true);
		AddPanel(TEXT("dictation-post-process-card"), TEXT("dictation-post-process-card"), TEXT("right-stack-below-routing"), true);
		AddPanel(TEXT("dictation-readiness-card"), TEXT("dictation-readiness-card"), TEXT("left-stack-below-history"), true);
		AddPanel(TEXT("dictation-hotkey-card"), TEXT("dictation-hotkey-card"), TEXT("left-stack-below-readiness"), true);
		AddPanel(TEXT("dictation-device-card"), TEXT("dictation-device-card"), TEXT("right-stack-below-post-process"), true);
		AddPanel(TEXT("dictation-audio-mode-card"), TEXT("dictation-audio-mode-card"), TEXT("right-stack-below-device"), true);
		AddPanel(TEXT("dictation-model-catalog-card"), TEXT("dictation-model-catalog-card"), TEXT("left-stack-below-hotkey"), true);
		AddPanel(TEXT("dictation-model-integrity-card"), TEXT("dictation-model-integrity-card"), TEXT("right-stack-below-audio-mode"), true);
		AddPanel(TEXT("dictation-model-unload-card"), TEXT("dictation-model-unload-card"), TEXT("right-stack-below-model-integrity"), true);

		AddAction(TEXT("start-external-dictation-capture"), TEXT("Space"), TEXT("dictation-readiness-card"));
		AddAction(TEXT("cancel-external-dictation-capture"), TEXT("Escape"), TEXT("dictation-readiness-card"));
		AddAction(TEXT("cycle-external-dictation-output-route"), TEXT("Tab"), TEXT("dictation-output-routing-card"));
		AddAction(TEXT("copy-latest-dictation-transcript"), TEXT("C"), TEXT("dictation-history-card"));
		AddAction(TEXT("paste-latest-dictation-transcript"), TEXT("V"), TEXT("dictation-output-routing-card"));
		AddAction(TEXT("dispatch-dictation-script-output"), TEXT("R"), TEXT("dictation-output-routing-card"));
		AddAction(TEXT("toggle-dictation-post-process-overlay"), TEXT("P"), TEXT("dictation-post-process-card"));
		AddAction(TEXT("reopen-speech-session"), TEXT("O"), TEXT("dictation-readiness-card"));
		AddAction(TEXT("inspect-provider-route"), TEXT("I"), TEXT("dictation-readiness-card"));
		AddAction(TEXT("inspect-dictation-global-hotkey"), TEXT("Ctrl+Space"), TEXT("dictation-hotkey-card"));
		AddAction(TEXT("cycle-dictation-input-device"), TEXT("Alt+]"), TEXT("dictation-device-card"));
		AddAction(TEXT("cycle-dictation-output-device"), TEXT("Alt+["), TEXT("dictation-device-card"));
		AddAction(TEXT("toggle-dictation-mute-while-recording"), TEXT("M"), TEXT("dictation-audio-mode-card"));
		AddAction(TEXT("toggle-dictation-microphone-mode"), TEXT("A"), TEXT("dictation-audio-mode-card"));
		AddAction(TEXT("inspect-local-model-catalog"), TEXT("L"), TEXT("dictation-model-catalog-card"));
		AddAction(TEXT("review-local-model-integrity"), TEXT("K"), TEXT("dictation-model-integrity-card"));
		AddAction(TEXT("review-local-model-unload-policy"), TEXT("U"), TEXT("dictation-model-unload-card"));
		return Profile;
	}

	TArray<FHyperTwistSpeechExternalDictationDeviceOption>
	BuildDefaultSpeechExternalDictationInputDeviceOptions()
	{
		auto MakeDeviceOption = [](
			const TCHAR* DeviceId,
			const TCHAR* DisplayLabel,
			const bool bDefaultRoute,
			const bool bSelectedRoute
		)
		{
			FHyperTwistSpeechExternalDictationDeviceOption DeviceOption;
			DeviceOption.DeviceId = DeviceId;
			DeviceOption.DisplayLabel = DisplayLabel;
			DeviceOption.DeviceRoleId = TEXT("input");
			DeviceOption.bDefaultRoute = bDefaultRoute;
			DeviceOption.bSelectedRoute = bSelectedRoute;
			return DeviceOption;
		};

		return {
			MakeDeviceOption(TEXT("system-default-input"), TEXT("System default microphone"), true, true),
			MakeDeviceOption(TEXT("selected-microphone"), TEXT("Selected microphone profile"), false, false),
			MakeDeviceOption(TEXT("clamshell-fallback-input"), TEXT("Clamshell microphone fallback"), false, false)
		};
	}

	TArray<FHyperTwistSpeechExternalDictationDeviceOption>
	BuildDefaultSpeechExternalDictationOutputDeviceOptions()
	{
		auto MakeDeviceOption = [](
			const TCHAR* DeviceId,
			const TCHAR* DisplayLabel,
			const bool bDefaultRoute,
			const bool bSelectedRoute
		)
		{
			FHyperTwistSpeechExternalDictationDeviceOption DeviceOption;
			DeviceOption.DeviceId = DeviceId;
			DeviceOption.DisplayLabel = DisplayLabel;
			DeviceOption.DeviceRoleId = TEXT("output");
			DeviceOption.bDefaultRoute = bDefaultRoute;
			DeviceOption.bSelectedRoute = bSelectedRoute;
			return DeviceOption;
		};

		return {
			MakeDeviceOption(TEXT("system-default-output"), TEXT("System default output device"), true, true),
			MakeDeviceOption(TEXT("selected-output-device"), TEXT("Selected output device profile"), false, false)
		};
	}

	FHyperTwistSpeechUsageCostDashboardShellProfile BuildDefaultSpeechUsageCostDashboardShellProfile(
		const FString& ProfileId
	)
	{
		FHyperTwistSpeechUsageCostDashboardShellProfile Profile;
		Profile.DashboardShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-usage-cost-dashboard");
		Profile.UsageSurfaceMode = TEXT("normalized-usage-summary-card");
		Profile.CostSurfaceMode = TEXT("estimate-first-cost-card");
		Profile.EscalationBannerMode = TEXT("route-and-budget-posture-banner");
		Profile.RefreshActionId = TEXT("refresh-provider-usage-cost-dashboard");
		Profile.RouteInspectActionId = TEXT("inspect-provider-route");
		Profile.BudgetInspectActionId = TEXT("review-provider-budget");
		Profile.bSupportsProviderSummary = true;
		Profile.bSupportsEstimateBadges = true;
		Profile.bSupportsQuotaEscalationBanner = true;
		Profile.bSupportsRouteDiagnostics = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("provider-summary-card"), TEXT("provider-summary-card"), TEXT("top-left"), true);
		AddPanel(TEXT("usage-meter-card"), TEXT("usage-meter-card"), TEXT("left-stack-below-provider"), true);
		AddPanel(TEXT("cost-estimate-card"), TEXT("cost-estimate-card"), TEXT("top-right"), true);
		AddPanel(TEXT("quota-state-card"), TEXT("quota-state-card"), TEXT("right-stack-below-cost"), true);
		AddPanel(TEXT("route-diagnostics-card"), TEXT("route-diagnostics-card"), TEXT("bottom-right"), true);

		AddAction(TEXT("refresh-provider-usage-cost-dashboard"), TEXT("F5"), TEXT("provider-summary-card"));
		AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("route-diagnostics-card"));
		AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("quota-state-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechUsageCostHistoryExportShellProfile
	BuildDefaultSpeechUsageCostHistoryExportShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile;
		Profile.HistoryExportShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-usage-cost-history-export");
		Profile.HistorySurfaceMode = TEXT("rolling-usage-cost-snapshot-history");
		Profile.ExportSurfaceMode = TEXT("first-party-summary-preview");
		Profile.RefreshActionId = TEXT("refresh-provider-usage-cost-history");
		Profile.ExportPreviewActionId = TEXT("preview-provider-usage-cost-export");
		Profile.CopySummaryActionId = TEXT("copy-provider-usage-cost-summary");
		Profile.RouteInspectActionId = TEXT("inspect-provider-route");
		Profile.BudgetInspectActionId = TEXT("review-provider-budget");
		Profile.RetainedHistoryEntryLimit = 12;
		Profile.bSupportsHistoryTimeline = true;
		Profile.bSupportsExportPreview = true;
		Profile.bSupportsCopySummary = true;
		Profile.bSupportsEstimateWatermark = true;
		Profile.bPreservesFirstPartySummaryOwnership = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("history-timeline-card"), TEXT("history-timeline-card"), TEXT("top-left"), true);
		AddPanel(TEXT("history-summary-card"), TEXT("history-summary-card"), TEXT("left-stack-below-history"), true);
		AddPanel(TEXT("export-preview-card"), TEXT("export-preview-card"), TEXT("top-right"), true);
		AddPanel(TEXT("export-readiness-card"), TEXT("export-readiness-card"), TEXT("right-stack-below-preview"), true);

		AddAction(TEXT("refresh-provider-usage-cost-history"), TEXT("F6"), TEXT("history-timeline-card"));
		AddAction(TEXT("preview-provider-usage-cost-export"), TEXT("E"), TEXT("export-preview-card"));
		AddAction(TEXT("copy-provider-usage-cost-summary"), TEXT("C"), TEXT("export-readiness-card"));
		AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("history-summary-card"));
		AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("export-readiness-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechProviderReceiptReviewShellProfile
	BuildDefaultSpeechProviderReceiptReviewShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechProviderReceiptReviewShellProfile Profile;
		Profile.ReceiptReviewShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-provider-receipt-review");
		Profile.ReceiptSurfaceMode = TEXT("posted-charge-review");
		Profile.VarianceSurfaceMode = TEXT("estimate-versus-posted-charge");
		Profile.RefreshActionId = TEXT("refresh-provider-receipt-review");
		Profile.PostedChargeInspectActionId = TEXT("inspect-provider-posted-charges");
		Profile.VarianceReviewActionId = TEXT("review-provider-charge-variance");
		Profile.RouteInspectActionId = TEXT("inspect-provider-route");
		Profile.BudgetInspectActionId = TEXT("review-provider-budget");
		Profile.RetainedReceiptEntryLimit = 12;
		Profile.bSupportsReceiptTimeline = true;
		Profile.bSupportsPostedChargeInspection = true;
		Profile.bSupportsVarianceReview = true;
		Profile.bSupportsEstimateOnlyFallback = true;
		Profile.bPreservesFirstPartyReceiptInspectionOwnership = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("receipt-timeline-card"), TEXT("receipt-timeline-card"), TEXT("top-left"), true);
		AddPanel(TEXT("posted-charge-summary-card"), TEXT("posted-charge-summary-card"), TEXT("left-stack-below-receipts"), true);
		AddPanel(TEXT("variance-review-card"), TEXT("variance-review-card"), TEXT("top-right"), true);
		AddPanel(TEXT("receipt-readiness-card"), TEXT("receipt-readiness-card"), TEXT("right-stack-below-variance"), true);

		AddAction(TEXT("refresh-provider-receipt-review"), TEXT("F7"), TEXT("receipt-timeline-card"));
		AddAction(TEXT("inspect-provider-posted-charges"), TEXT("I"), TEXT("posted-charge-summary-card"));
		AddAction(TEXT("review-provider-charge-variance"), TEXT("V"), TEXT("variance-review-card"));
		AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("receipt-readiness-card"));
		AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("receipt-readiness-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechProviderBillingSettlementShellProfile
	BuildDefaultSpeechProviderBillingSettlementShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechProviderBillingSettlementShellProfile Profile;
		Profile.BillingSettlementShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-provider-billing-settlement");
		Profile.SettlementSurfaceMode = TEXT("posted-charge-settlement-assessment");
		Profile.InvoiceReconciliationMode = TEXT("estimate-versus-provider-invoice");
		Profile.RefreshActionId = TEXT("refresh-provider-billing-settlement");
		Profile.InvoiceReconciliationActionId = TEXT("inspect-provider-invoice-reconciliation");
		Profile.SettlementReadinessActionId = TEXT("review-provider-settlement-readiness");
		Profile.RouteInspectActionId = TEXT("inspect-provider-route");
		Profile.BudgetInspectActionId = TEXT("review-provider-budget");
		Profile.RetainedSettlementEntryLimit = 12;
		Profile.bSupportsSettlementTimeline = true;
		Profile.bSupportsInvoiceReconciliation = true;
		Profile.bSupportsSettlementReadinessReview = true;
		Profile.bSupportsEstimateOnlyFallback = true;
		Profile.bPreservesFirstPartySettlementOwnership = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("settlement-timeline-card"), TEXT("settlement-timeline-card"), TEXT("top-left"), true);
		AddPanel(TEXT("invoice-reconciliation-card"), TEXT("invoice-reconciliation-card"), TEXT("top-right"), true);
		AddPanel(TEXT("settlement-summary-card"), TEXT("settlement-summary-card"), TEXT("left-stack-below-settlement"), true);
		AddPanel(TEXT("settlement-readiness-card"), TEXT("settlement-readiness-card"), TEXT("right-stack-below-reconciliation"), true);

		AddAction(TEXT("refresh-provider-billing-settlement"), TEXT("F8"), TEXT("settlement-timeline-card"));
		AddAction(TEXT("inspect-provider-invoice-reconciliation"), TEXT("R"), TEXT("invoice-reconciliation-card"));
		AddAction(TEXT("review-provider-settlement-readiness"), TEXT("S"), TEXT("settlement-readiness-card"));
		AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("settlement-summary-card"));
		AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("settlement-readiness-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechProviderSettlementExceptionShellProfile
	BuildDefaultSpeechProviderSettlementExceptionShellProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechProviderSettlementExceptionShellProfile Profile;
		Profile.SettlementExceptionShellProfileId = ProfileId;
		Profile.ShellKind = TEXT("operator-provider-settlement-exception");
		Profile.ExceptionSurfaceMode = TEXT("settlement-exception-triage");
		Profile.ExternalPortalHandoffMode = TEXT("reference-only-provider-portal-handoff");
		Profile.RefreshActionId = TEXT("refresh-provider-settlement-exceptions");
		Profile.ExceptionInspectActionId = TEXT("inspect-provider-settlement-exception");
		Profile.ExternalPortalHandoffActionId =
			TEXT("review-provider-external-portal-handoff");
		Profile.RouteInspectActionId = TEXT("inspect-provider-route");
		Profile.BudgetInspectActionId = TEXT("review-provider-budget");
		Profile.RetainedExceptionEntryLimit = 12;
		Profile.bSupportsExceptionTimeline = true;
		Profile.bSupportsExternalPortalHandoff = true;
		Profile.bSupportsSettlementExceptionReview = true;
		Profile.bSupportsPendingChargeExceptions = true;
		Profile.bPreservesFirstPartyHandoffOwnership = true;

		auto AddPanel = [&Profile](
			const TCHAR* PanelId,
			const TCHAR* PanelKind,
			const TCHAR* AnchorId,
			const bool bVisibleByDefault
		)
		{
			FHyperTwistSpeechShellPanelLayout Panel;
			Panel.PanelId = PanelId;
			Panel.PanelKind = PanelKind;
			Panel.AnchorId = AnchorId;
			Panel.bVisibleByDefault = bVisibleByDefault;
			Profile.Panels.Add(Panel);
		};

		auto AddAction = [&Profile](
			const TCHAR* ActionId,
			const TCHAR* InputBinding,
			const TCHAR* SurfaceId
		)
		{
			FHyperTwistSpeechShellActionBinding ActionBinding;
			ActionBinding.ActionId = ActionId;
			ActionBinding.InputBinding = InputBinding;
			ActionBinding.SurfaceId = SurfaceId;
			Profile.ActionBindings.Add(ActionBinding);
		};

		AddPanel(TEXT("settlement-exception-timeline-card"), TEXT("settlement-exception-timeline-card"), TEXT("top-left"), true);
		AddPanel(TEXT("external-portal-handoff-card"), TEXT("external-portal-handoff-card"), TEXT("top-right"), true);
		AddPanel(TEXT("exception-summary-card"), TEXT("exception-summary-card"), TEXT("left-stack-below-settlement"), true);
		AddPanel(TEXT("exception-readiness-card"), TEXT("exception-readiness-card"), TEXT("right-stack-below-handoff"), true);

		AddAction(TEXT("refresh-provider-settlement-exceptions"), TEXT("F9"), TEXT("settlement-exception-timeline-card"));
		AddAction(TEXT("inspect-provider-settlement-exception"), TEXT("E"), TEXT("settlement-exception-timeline-card"));
		AddAction(TEXT("review-provider-external-portal-handoff"), TEXT("H"), TEXT("external-portal-handoff-card"));
		AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("exception-summary-card"));
		AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("exception-readiness-card"));
		AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
		return Profile;
	}

	FHyperTwistSpeechModelPayloadDescriptor MakeSpeechModelPayloadDescriptor(
		const TCHAR* PayloadId,
		const TCHAR* PayloadKind,
		const TCHAR* ModelFamily,
		const TCHAR* VariantId,
		const TCHAR* ArtifactName,
		const TCHAR* RelativePathHint,
		const TCHAR* SourceDocumentPath,
		const TCHAR* AcquisitionMode,
		const TCHAR* IntegrityCheckKind,
		const TCHAR* IntegrityCheckValue,
		const int32 ApproximateSizeMiB,
		const bool bOptionalForSession
	)
	{
		FHyperTwistSpeechModelPayloadDescriptor Descriptor;
		Descriptor.PayloadId = PayloadId;
		Descriptor.PayloadKind = PayloadKind;
		Descriptor.ModelFamily = ModelFamily;
		Descriptor.VariantId = VariantId;
		Descriptor.ArtifactName = ArtifactName;
		Descriptor.RelativePathHint = RelativePathHint;
		Descriptor.SourceDocumentPath = SourceDocumentPath;
		Descriptor.AcquisitionMode = AcquisitionMode;
		Descriptor.IntegrityCheckKind = IntegrityCheckKind;
		Descriptor.IntegrityCheckValue = IntegrityCheckValue;
		Descriptor.ApproximateSizeMiB = ApproximateSizeMiB;
		Descriptor.bOptionalForSession = bOptionalForSession;
		Descriptor.bUserSuppliedOnly = true;
		Descriptor.bBundledWithCodeDistribution = false;
		return Descriptor;
	}

	FHyperTwistSpeechPayloadCustodyProfile BuildDefaultSpeechPayloadCustodyProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechPayloadCustodyProfile Profile;
		Profile.PayloadCustodyProfileId = ProfileId;
		Profile.PayloadReviewPosture = TEXT("independent-payload-review-required");
		Profile.ShippingPosture = TEXT("not-shipped-in-packet");
		Profile.DownloadWorkflowPosture = TEXT("deferred-out-of-packet");
		Profile.ProvisioningPosture = TEXT("user-supplied-or-sidecar-managed");
		Profile.CodeLicenseBoundary = TEXT("code-license-reviewed-separately");
		Profile.bRequiresIndependentPayloadReview = true;
		Profile.bAllowsBundledPayloadRedistribution = false;
		Profile.bAllowsRuntimeDownloadInCurrentPacket = false;
		Profile.bSupportsUserManagedPayloads = true;
		Profile.bSupportsSidecarManagedPayloads = true;
		Profile.bRequiresIntegrityVerification = true;
		Profile.bPreservesProviderNeutrality = true;
		return Profile;
	}

	TArray<FString> BuildDefaultSpeechProviderModelIds()
	{
		return {
			TEXT("speech-model/whisper.cpp/base.en"),
			TEXT("speech-vad/whisper.cpp/silero-v6.2.0")
		};
	}

	TArray<FString> BuildDefaultSpeechProviderCapabilityFlags()
	{
		return {
			TEXT("transcribe"),
			TEXT("vadSegments"),
			TEXT("grammarHints"),
			TEXT("microphoneCaptureShell"),
			TEXT("devicePermissionShell"),
			TEXT("captureRouteReadinessShell"),
			TEXT("captureRouteRetry"),
			TEXT("devicePermissionWorkflow"),
			TEXT("devicePermissionSettingsHandoff"),
			TEXT("devicePermissionRecheck"),
			TEXT("streamingPreview"),
			TEXT("manualTranscriptCommit"),
			TEXT("batchedTranscribe"),
			TEXT("wordTimestamps"),
			TEXT("languageDetection"),
			TEXT("promptHints"),
			TEXT("normalizedUsageEvents"),
			TEXT("normalizedCostEvents"),
			TEXT("quotaRateLimitState"),
			TEXT("providerUsageCostDashboardShell"),
			TEXT("providerQuotaEscalationBanner"),
			TEXT("providerRouteCostDiagnostics"),
			TEXT("providerUsageCostHistoryShell"),
			TEXT("providerUsageCostExportPreview"),
			TEXT("providerUsageCostSummaryCopy"),
			TEXT("providerReceiptReviewShell"),
			TEXT("providerPostedChargeInspection"),
			TEXT("providerChargeVarianceReview"),
			TEXT("providerBillingSettlementShell"),
			TEXT("providerInvoiceReconciliation"),
			TEXT("providerSettlementReadinessReview"),
			TEXT("providerSettlementExceptionShell"),
			TEXT("providerExternalPortalHandoff"),
			TEXT("providerSettlementExceptionReview")
		};
	}

	TArray<FString> BuildDefaultSpeechRoutingEligibleProviderClasses()
	{
		return {
			TEXT("official-direct-provider"),
			TEXT("openai-compatible-custom-endpoint"),
			TEXT("byok-endpoint"),
			TEXT("managed-gateway-provider"),
			TEXT("local-self-hosted-provider"),
			TEXT("bounded-speech-sidecar-service"),
			TEXT("first-party-mock-provider")
		};
	}

	TArray<FString> BuildDefaultSpeechRoutingEligibleEndpointClasses()
	{
		return {
			TEXT("official-http-api"),
			TEXT("openai-compatible-http-api"),
			TEXT("managed-gateway-http"),
			TEXT("local-self-hosted-http"),
			TEXT("in-process-mock")
		};
	}

	TArray<FString> BuildDefaultSpeechRoutingRequiredCapabilities()
	{
		return {
			TEXT("transcribe"),
			TEXT("grammarHints"),
			TEXT("manualTranscriptCommit")
		};
	}

	TArray<FString> BuildDefaultSpeechRoutingSupportedTaskKinds()
	{
		return {
			TEXT("transcribe")
		};
	}

	TArray<FString> BuildDefaultSpeechUsageMeterKinds()
	{
		return {
			TEXT("audio-seconds"),
			TEXT("request-count"),
			TEXT("session-count")
		};
	}

	TArray<FString> BuildDefaultSpeechUsageCurrencyCodes()
	{
		return {
			TEXT("USD")
		};
	}

	FHyperTwistSpeechProviderProfile BuildDefaultMockSpeechProviderProfile()
	{
		FHyperTwistSpeechProviderProfile Profile;
		Profile.ProviderProfileId = TEXT("speech-provider/mock-offline-profile-v1");
		Profile.DisplayLabel = TEXT("Mock Offline Speech");
		Profile.ProviderClass = TEXT("first-party-mock-provider");
		Profile.EndpointClass = TEXT("in-process-mock");
		Profile.EndpointReferenceId = TEXT("speech/provider-profile/mock-offline");
		Profile.EndpointBaseUrl = TEXT("in-process://mock");
		Profile.AuthMaterialSource = TEXT("not-required");
		Profile.AuthReferenceId.Reset();
		Profile.ModelSelectionMode = TEXT("per-profile-model-map");
		Profile.SupportedModelIds = BuildDefaultSpeechProviderModelIds();
		Profile.CapabilityFlags = BuildDefaultSpeechProviderCapabilityFlags();
		Profile.bEnabled = true;
		Profile.bUserLabeled = false;
		Profile.bSupportsEnableDisable = true;
		Profile.bSupportsCustomBaseUrl = false;
		Profile.bPreservesFirstPartyCustody = true;
		return Profile;
	}

	FHyperTwistSpeechProviderProfile BuildDefaultHttpSpeechProviderProfile(
		const FString& ProviderLabel,
		const FString& ServiceEndpoint
	)
	{
		FHyperTwistSpeechProviderProfile Profile;
		Profile.ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1");
		Profile.DisplayLabel = ProviderLabel.IsEmpty() ? TEXT("Local HTTP Speech Sidecar") : ProviderLabel;
		Profile.ProviderClass = TEXT("bounded-speech-sidecar-service");
		Profile.EndpointClass = TEXT("local-self-hosted-http");
		Profile.EndpointReferenceId = TEXT("speech/provider-profile/local-http-sidecar");
		Profile.EndpointBaseUrl = ServiceEndpoint;
		Profile.AuthMaterialSource = TEXT("first-party-out-of-band-secret-reference");
		Profile.AuthReferenceId = TEXT("speech/byok/local-http-sidecar/default");
		Profile.ModelSelectionMode = TEXT("per-profile-model-map");
		Profile.SupportedModelIds = BuildDefaultSpeechProviderModelIds();
		Profile.CapabilityFlags = BuildDefaultSpeechProviderCapabilityFlags();
		Profile.bEnabled = true;
		Profile.bUserLabeled = true;
		Profile.bSupportsEnableDisable = true;
		Profile.bSupportsCustomBaseUrl = true;
		Profile.bPreservesFirstPartyCustody = true;
		return Profile;
	}

	FHyperTwistSpeechProviderRoutingPolicy BuildDefaultMockSpeechProviderRoutingPolicy()
	{
		FHyperTwistSpeechProviderRoutingPolicy Policy;
		Policy.ProviderRoutingPolicyId = TEXT("speech-provider-routing/local-offline-mock-first-v1");
		Policy.PolicyKind = TEXT("speech-provider-routing");
		Policy.RouteSelectionMode = TEXT("local-offline-mock-first");
		Policy.FallbackMode = TEXT("fail-closed");
		Policy.WorkflowPolicyState = TEXT("first-party-provider-policy-governed");
		Policy.FailureEscalationMode = TEXT("preserve-local-verification-route");
		Policy.UserOverridePosture = TEXT("client-kind-and-profile-override-supported");
		Policy.EligibleProviderClasses = BuildDefaultSpeechRoutingEligibleProviderClasses();
		Policy.EligibleEndpointClasses = BuildDefaultSpeechRoutingEligibleEndpointClasses();
		Policy.RequiredCapabilityFlags = BuildDefaultSpeechRoutingRequiredCapabilities();
		Policy.SupportedTaskKinds = BuildDefaultSpeechRoutingSupportedTaskKinds();
		Policy.bAllowProviderBackedRoutes = false;
		Policy.bAllowMockVerificationRoutes = true;
		Policy.bAllowOpenAiCompatibleCustomEndpointRoutes = true;
		Policy.bAllowUserLabeledByokRoutes = true;
		Policy.bAllowManagedGatewayRoutes = true;
		Policy.bAllowLocalSelfHostedRoutes = true;
		Policy.bRespectsProfileEnableDisable = true;
		Policy.bAllowFailClosedWhenNoEligibleRoute = true;
		Policy.bAllowHealthPostureFallback = false;
		Policy.bPreservesFirstPartyRoutingOwnership = true;
		Policy.bAllowsDonorOwnedRoutingLanguage = false;
		return Policy;
	}

	FHyperTwistSpeechProviderRoutingPolicy BuildDefaultProviderBackedSpeechProviderRoutingPolicy()
	{
		FHyperTwistSpeechProviderRoutingPolicy Policy;
		Policy.ProviderRoutingPolicyId = TEXT("speech-provider-routing/provider-backed-sidecar-first-v1");
		Policy.PolicyKind = TEXT("speech-provider-routing");
		Policy.RouteSelectionMode = TEXT("provider-backed-sidecar-first");
		Policy.FallbackMode = TEXT("health-posture-only");
		Policy.WorkflowPolicyState = TEXT("first-party-provider-policy-governed");
		Policy.FailureEscalationMode = TEXT("fail-closed-and-report-health");
		Policy.UserOverridePosture = TEXT("profile-or-client-kind-override-supported");
		Policy.EligibleProviderClasses = BuildDefaultSpeechRoutingEligibleProviderClasses();
		Policy.EligibleEndpointClasses = BuildDefaultSpeechRoutingEligibleEndpointClasses();
		Policy.RequiredCapabilityFlags = BuildDefaultSpeechRoutingRequiredCapabilities();
		Policy.SupportedTaskKinds = BuildDefaultSpeechRoutingSupportedTaskKinds();
		Policy.bAllowProviderBackedRoutes = true;
		Policy.bAllowMockVerificationRoutes = true;
		Policy.bAllowOpenAiCompatibleCustomEndpointRoutes = true;
		Policy.bAllowUserLabeledByokRoutes = true;
		Policy.bAllowManagedGatewayRoutes = true;
		Policy.bAllowLocalSelfHostedRoutes = true;
		Policy.bRespectsProfileEnableDisable = true;
		Policy.bAllowFailClosedWhenNoEligibleRoute = true;
		Policy.bAllowHealthPostureFallback = true;
		Policy.bPreservesFirstPartyRoutingOwnership = true;
		Policy.bAllowsDonorOwnedRoutingLanguage = false;
		return Policy;
	}

	FHyperTwistSpeechProviderRouteDecision BuildSpeechProviderRouteDecision(
		const FHyperTwistSpeechProviderRoutingPolicy& Policy,
		const FHyperTwistSpeechProviderProfile& Profile,
		const FString& SelectedServiceLaneId,
		const FString& DecisionSource,
		const FString& RouteStateId,
		const FString& DecisionReason,
		const FString& FailureReason,
		const bool bProviderBackedRouteRequested,
		const bool bProviderBackedRouteSelected,
		const bool bUsedFallbackHealthPosture,
		const bool bRouteReady
	)
	{
		FHyperTwistSpeechProviderRouteDecision Decision;
		Decision.RouteDecisionId = FString::Printf(
			TEXT("speech-route-decision/%s"),
			*Profile.ProviderProfileId
		);
		Decision.ProviderRoutingPolicyId = Policy.ProviderRoutingPolicyId;
		Decision.DecisionSource = DecisionSource;
		Decision.RequestedProviderProfileId = Profile.ProviderProfileId;
		Decision.SelectedProviderProfileId = Profile.ProviderProfileId;
		Decision.SelectedProviderClass = Profile.ProviderClass;
		Decision.SelectedEndpointClass = Profile.EndpointClass;
		Decision.SelectedServiceLaneId = SelectedServiceLaneId.IsEmpty()
			? TEXT("speech/python-service")
			: SelectedServiceLaneId;
		Decision.SelectedTransportKind = Profile.EndpointClass.Equals(TEXT("in-process-mock"), ESearchCase::IgnoreCase)
			? TEXT("in-process")
			: TEXT("http");
		Decision.RouteStateId = RouteStateId;
		Decision.DecisionReason = DecisionReason;
		Decision.FailureReason = FailureReason;
		Decision.FallbackMode = Policy.FallbackMode;
		Decision.bProviderBackedRouteRequested = bProviderBackedRouteRequested;
		Decision.bProviderBackedRouteSelected = bProviderBackedRouteSelected;
		Decision.bUsedFallbackHealthPosture = bUsedFallbackHealthPosture;
		Decision.bSelectedProfileEnabled = Profile.bEnabled;
		Decision.bSelectedCustomEndpointRoute =
			Profile.bUserLabeled
			&& Profile.bSupportsCustomBaseUrl
			&& !Profile.EndpointBaseUrl.IsEmpty()
			&& !Profile.EndpointBaseUrl.Contains(TEXT("127.0.0.1"), ESearchCase::IgnoreCase);
		Decision.bRouteReady = bRouteReady;
		return Decision;
	}

	FHyperTwistSpeechUsageCostAccountingProfile BuildDefaultSpeechUsageCostAccountingProfile(
		const FString& ProfileId
	)
	{
		FHyperTwistSpeechUsageCostAccountingProfile Profile;
		Profile.UsageCostAccountingProfileId = ProfileId;
		Profile.AccountingKind = TEXT("normalized-usage-cost-events");
		Profile.UsageAggregationMode = TEXT("session-and-health-summary");
		Profile.CostAggregationMode = TEXT("estimate-first-with-provider-receipt-optional");
		Profile.QuotaVisibilityMode = TEXT("first-party-health-surface");
		Profile.EscalationMode = TEXT("surface-budget-and-quota-state");
		Profile.UserOverridePosture = TEXT("profile-or-session-override-supported");
		Profile.NormalizedMeterKinds = BuildDefaultSpeechUsageMeterKinds();
		Profile.NormalizedCurrencyCodes = BuildDefaultSpeechUsageCurrencyCodes();
		Profile.bSupportsProviderReceiptNormalization = true;
		Profile.bSupportsEstimateOnlyMode = true;
		Profile.bSupportsQuotaSnapshots = true;
		Profile.bSupportsRateLimitSnapshots = true;
		Profile.bPreservesFirstPartyAccountingOwnership = true;
		Profile.bAllowsDonorOwnedCostGovernance = false;
		return Profile;
	}

	FHyperTwistSpeechNormalizedUsageEvent BuildDefaultSpeechUsageEvent(
		const FHyperTwistSpeechUsageCostAccountingProfile& AccountingProfile,
		const FHyperTwistSpeechProviderProfile& ProviderProfile,
		const FString& ServiceLaneId,
		const FString& EventKind,
		const FString& AggregationWindowId,
		const FString& RawEventReferenceId,
		const float ReportedQuantity,
		const float BilledQuantity,
		const bool bDerivedFromProviderReceipt,
		const bool bEstimateOnly
	)
	{
		FHyperTwistSpeechNormalizedUsageEvent Event;
		Event.UsageEventId = FString::Printf(
			TEXT("speech-usage-event/%s"),
			*ProviderProfile.ProviderProfileId
		);
		Event.UsageCostAccountingProfileId = AccountingProfile.UsageCostAccountingProfileId;
		Event.ProviderProfileId = ProviderProfile.ProviderProfileId;
		Event.ServiceLaneId = ServiceLaneId.IsEmpty()
			? TEXT("speech/python-service")
			: ServiceLaneId;
		Event.EventKind = EventKind.IsEmpty()
			? TEXT("bounded-session-usage-summary")
			: EventKind;
		Event.MeterKind = TEXT("audio-seconds");
		Event.UsageUnitKind = TEXT("audio-seconds");
		Event.AggregationWindowId = AggregationWindowId.IsEmpty()
			? TEXT("current-session")
			: AggregationWindowId;
		Event.CapturedAtUtc = TEXT("2026-05-25T00:00:00Z");
		Event.RawEventReferenceId = RawEventReferenceId.IsEmpty()
			? TEXT("speech-session-default")
			: RawEventReferenceId;
		Event.ReportedQuantity = ReportedQuantity;
		Event.BilledQuantity = BilledQuantity;
		Event.bDerivedFromProviderReceipt = bDerivedFromProviderReceipt;
		Event.bEstimateOnly = bEstimateOnly;
		return Event;
	}

	FHyperTwistSpeechNormalizedCostEvent BuildDefaultSpeechCostEvent(
		const FHyperTwistSpeechUsageCostAccountingProfile& AccountingProfile,
		const FHyperTwistSpeechProviderProfile& ProviderProfile,
		const FString& ServiceLaneId,
		const FString& EventKind,
		const FString& AggregationWindowId,
		const float EstimatedCost,
		const float ReportedCost,
		const bool bEstimateOnly,
		const bool bHasProviderPostedCharge
	)
	{
		FHyperTwistSpeechNormalizedCostEvent Event;
		Event.CostEventId = FString::Printf(
			TEXT("speech-cost-event/%s"),
			*ProviderProfile.ProviderProfileId
		);
		Event.UsageCostAccountingProfileId = AccountingProfile.UsageCostAccountingProfileId;
		Event.ProviderProfileId = ProviderProfile.ProviderProfileId;
		Event.ServiceLaneId = ServiceLaneId.IsEmpty()
			? TEXT("speech/python-service")
			: ServiceLaneId;
		Event.EventKind = EventKind.IsEmpty()
			? TEXT("bounded-session-cost-summary")
			: EventKind;
		Event.CurrencyCode = TEXT("USD");
		Event.PricingSourceId = bHasProviderPostedCharge
			? TEXT("provider-posted-charge")
			: TEXT("first-party-estimate");
		Event.AggregationWindowId = AggregationWindowId.IsEmpty()
			? TEXT("current-session")
			: AggregationWindowId;
		Event.CapturedAtUtc = TEXT("2026-05-25T00:00:00Z");
		Event.EstimatedCost = EstimatedCost;
		Event.ReportedCost = ReportedCost;
		Event.bEstimateOnly = bEstimateOnly;
		Event.bHasProviderPostedCharge = bHasProviderPostedCharge;
		return Event;
	}

	FHyperTwistSpeechQuotaRateLimitState BuildDefaultSpeechQuotaRateLimitState(
		const FHyperTwistSpeechUsageCostAccountingProfile& AccountingProfile,
		const FHyperTwistSpeechProviderProfile& ProviderProfile,
		const FString& ServiceLaneId,
		const FString& StateReason,
		const bool bQuotaKnown,
		const bool bRateLimited,
		const bool bHardBlocked,
		const int32 RemainingRequestCount,
		const int32 RemainingAudioSeconds,
		const float RemainingEstimatedSpendUsd
	)
	{
		FHyperTwistSpeechQuotaRateLimitState State;
		State.QuotaStateId = FString::Printf(
			TEXT("speech-quota-state/%s"),
			*ProviderProfile.ProviderProfileId
		);
		State.UsageCostAccountingProfileId = AccountingProfile.UsageCostAccountingProfileId;
		State.ProviderProfileId = ProviderProfile.ProviderProfileId;
		State.ServiceLaneId = ServiceLaneId.IsEmpty()
			? TEXT("speech/python-service")
			: ServiceLaneId;
		State.RateLimitWindowId = TEXT("per-minute");
		State.ResetAtUtc = TEXT("2026-05-25T00:01:00Z");
		State.StateReason = StateReason.IsEmpty() ? TEXT("within-budget") : StateReason;
		State.RemainingRequestCount = RemainingRequestCount;
		State.RemainingAudioSeconds = RemainingAudioSeconds;
		State.RemainingEstimatedSpendUsd = RemainingEstimatedSpendUsd;
		State.bQuotaKnown = bQuotaKnown;
		State.bRateLimited = bRateLimited;
		State.bHardBlocked = bHardBlocked;
		return State;
	}

	FHyperTwistSpeechByokCustodyProfile BuildDefaultSpeechByokCustodyProfile(const FString& ProfileId)
	{
		FHyperTwistSpeechByokCustodyProfile Profile;
		Profile.ByokCustodyProfileId = ProfileId;
		Profile.KeyCustodyPosture = TEXT("first-party-user-supplied");
		Profile.EndpointCustodyPosture = TEXT("first-party-custom-endpoint-owned");
		Profile.SecretStoragePosture = TEXT("out-of-band-secret-reference-only");
		Profile.ProfileLabelingPosture = TEXT("user-labeled-byok-profile-supported");
		Profile.EnablementPosture = TEXT("per-profile-enable-disable-supported");
		Profile.SupportedProviderClasses = {
			TEXT("official-direct-provider"),
			TEXT("openai-compatible-custom-endpoint"),
			TEXT("byok-endpoint"),
			TEXT("managed-gateway-provider"),
			TEXT("local-self-hosted-provider"),
			TEXT("bounded-speech-sidecar-service")
		};
		Profile.bSupportsOfficialProviderProfiles = true;
		Profile.bSupportsOpenAiCompatibleCustomEndpoints = true;
		Profile.bSupportsManagedGatewayProfiles = true;
		Profile.bSupportsLocalSelfHostedProfiles = true;
		Profile.bSupportsBoundedSidecarProfiles = true;
		Profile.bSupportsUserLabeledProfiles = true;
		Profile.bSupportsPerProfileModelMaps = true;
		Profile.bSupportsPerProfileAuthMaterial = true;
		Profile.bSupportsEnableDisableControls = true;
		Profile.bStoresSecretsOutOfBand = true;
		Profile.bPreservesProviderNeutrality = true;
		Profile.bAllowsDonorOwnedKeyCustody = false;
		return Profile;
	}

	TArray<FHyperTwistSpeechModelPayloadDescriptor> BuildDefaultSpeechModelPayloads()
	{
		return {
			MakeSpeechModelPayloadDescriptor(
				TEXT("speech-model/whisper.cpp/base.en"),
				TEXT("whisper-ggml-model"),
				TEXT("whisper"),
				TEXT("base.en"),
				TEXT("ggml-base.en.bin"),
				TEXT("models/ggml-base.en.bin"),
				TEXT("whisper.cpp/models/README.md"),
				TEXT("manual-download-or-convert"),
				TEXT("sha1"),
				TEXT("137c40403d78fd54d454da0f9bd998f78703390c"),
				142,
				false
			),
			MakeSpeechModelPayloadDescriptor(
				TEXT("speech-vad/whisper.cpp/silero-v6.2.0"),
				TEXT("whisper-vad-model"),
				TEXT("silero-vad"),
				TEXT("silero-v6.2.0"),
				TEXT("ggml-silero-v6.2.0.bin"),
				TEXT("models/ggml-silero-v6.2.0.bin"),
				TEXT("whisper.cpp/README.md"),
				TEXT("manual-download-or-convert"),
				TEXT(""),
				TEXT(""),
				2,
				true
			)
		};
	}

	void ApplySpeechProviderProfileDefaults(
		FHyperTwistSpeechSessionConfig& SessionConfig,
		const bool bUseMockClient
	)
	{
		if (SessionConfig.ProviderProfileId.IsEmpty()
			&& SessionConfig.ProviderProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderProfileId = SessionConfig.ProviderProfileDefinition.ProviderProfileId;
		}
		if (SessionConfig.ProviderProfileId.IsEmpty())
		{
			SessionConfig.ProviderProfileId = bUseMockClient
				? TEXT("speech-provider/mock-offline-profile-v1")
				: TEXT("speech-provider/local-http-sidecar-profile-v1");
		}
		if (!SessionConfig.ProviderProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderProfileDefinition = bUseMockClient
				? BuildDefaultMockSpeechProviderProfile()
				: BuildDefaultHttpSpeechProviderProfile(
					TEXT("Local HTTP Speech Sidecar"),
					TEXT("http://127.0.0.1:8766")
				);
		}
		SessionConfig.ProviderProfileId = SessionConfig.ProviderProfileDefinition.ProviderProfileId;
		if (SessionConfig.ByokCustodyProfileId.IsEmpty()
			&& SessionConfig.ByokCustodyProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ByokCustodyProfileId = SessionConfig.ByokCustodyProfileDefinition.ByokCustodyProfileId;
		}
		if (SessionConfig.ByokCustodyProfileId.IsEmpty())
		{
			SessionConfig.ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1");
		}
		if (!SessionConfig.ByokCustodyProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ByokCustodyProfileDefinition =
				BuildDefaultSpeechByokCustodyProfile(SessionConfig.ByokCustodyProfileId);
		}
		SessionConfig.ByokCustodyProfileId = SessionConfig.ByokCustodyProfileDefinition.ByokCustodyProfileId;
	}

	void ApplySpeechProviderRoutingDefaults(
		FHyperTwistSpeechSessionConfig& SessionConfig,
		const bool bUseMockClient
	)
	{
		if (SessionConfig.ProviderRoutingPolicyId.IsEmpty()
			&& SessionConfig.ProviderRoutingPolicyDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderRoutingPolicyId =
				SessionConfig.ProviderRoutingPolicyDefinition.ProviderRoutingPolicyId;
		}
		if (SessionConfig.ProviderRoutingPolicyId.IsEmpty())
		{
			SessionConfig.ProviderRoutingPolicyId = bUseMockClient
				? TEXT("speech-provider-routing/local-offline-mock-first-v1")
				: TEXT("speech-provider-routing/provider-backed-sidecar-first-v1");
		}
		if (!SessionConfig.ProviderRoutingPolicyDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderRoutingPolicyDefinition = bUseMockClient
				? BuildDefaultMockSpeechProviderRoutingPolicy()
				: BuildDefaultProviderBackedSpeechProviderRoutingPolicy();
		}
		SessionConfig.ProviderRoutingPolicyId =
			SessionConfig.ProviderRoutingPolicyDefinition.ProviderRoutingPolicyId;

		const FHyperTwistSpeechProviderProfile EffectiveProfile =
			SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderProfileDefinition
				: (bUseMockClient
					? BuildDefaultMockSpeechProviderProfile()
					: BuildDefaultHttpSpeechProviderProfile(
						TEXT("Local HTTP Speech Sidecar"),
						TEXT("http://127.0.0.1:8766")
					));
		const FString SelectedServiceLaneId = SessionConfig.OrchestrationProfile.ServiceLaneId;

		FString RouteStateId;
		FString DecisionReason;
		FString FailureReason;
		bool bRouteReady = true;

		if (!EffectiveProfile.bEnabled)
		{
			RouteStateId = TEXT("route-disabled");
			DecisionReason = TEXT("selected-provider-profile-disabled");
			FailureReason = TEXT("selected-provider-profile-disabled");
			bRouteReady = false;
		}
		else if (bUseMockClient)
		{
			RouteStateId = TEXT("route-ready");
			DecisionReason = TEXT("mock-verification-route-selected");
		}
		else if (EffectiveProfile.EndpointBaseUrl.IsEmpty())
		{
			RouteStateId = TEXT("route-awaiting-endpoint");
			DecisionReason = TEXT("provider-backed-sidecar-route-unavailable");
			FailureReason = TEXT("service-base-url-missing");
			bRouteReady = false;
		}
		else
		{
			RouteStateId = TEXT("route-ready");
			DecisionReason = TEXT("provider-backed-sidecar-route-selected");
		}

		SessionConfig.ProviderRouteDecision = BuildSpeechProviderRouteDecision(
			SessionConfig.ProviderRoutingPolicyDefinition,
			EffectiveProfile,
			SelectedServiceLaneId,
			TEXT("session-config-default"),
			RouteStateId,
			DecisionReason,
			FailureReason,
			!bUseMockClient,
			!bUseMockClient,
			false,
			bRouteReady
		);
	}

	void ApplySpeechPayloadCustodyDefaults(FHyperTwistSpeechSessionConfig& SessionConfig)
	{
		if (SessionConfig.PayloadCustodyProfileId.IsEmpty())
		{
			SessionConfig.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1");
		}
		if (!SessionConfig.PayloadCustodyProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.PayloadCustodyProfileDefinition =
				BuildDefaultSpeechPayloadCustodyProfile(SessionConfig.PayloadCustodyProfileId);
		}
		if (SessionConfig.RequiredModelPayloads.Num() <= 0)
		{
			SessionConfig.RequiredModelPayloads = BuildDefaultSpeechModelPayloads();
		}
	}

	void ApplySpeechExternalDictationDefaults(FHyperTwistSpeechSessionConfig& SessionConfig)
	{
		if (SessionConfig.ExternalDictationShellProfileId.IsEmpty()
			&& SessionConfig.ExternalDictationShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ExternalDictationShellProfileId =
				SessionConfig.ExternalDictationShellProfileDefinition
					.ExternalDictationShellProfileId;
		}
		if (SessionConfig.ExternalDictationShellProfileId.IsEmpty())
		{
			SessionConfig.ExternalDictationShellProfileId =
				TEXT("speech-external-dictation-shell-v1");
		}
		if (!SessionConfig.ExternalDictationShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ExternalDictationShellProfileDefinition =
				BuildDefaultSpeechExternalDictationShellProfile(
					SessionConfig.ExternalDictationShellProfileId
				);
		}
		SessionConfig.ExternalDictationShellProfileId =
			SessionConfig.ExternalDictationShellProfileDefinition
				.ExternalDictationShellProfileId;
	}

	void ApplySpeechUsageCostDefaults(FHyperTwistSpeechSessionConfig& SessionConfig)
	{
		if (SessionConfig.UsageCostAccountingProfileId.IsEmpty()
			&& SessionConfig.UsageCostAccountingProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.UsageCostAccountingProfileId =
				SessionConfig.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId;
		}
		if (SessionConfig.UsageCostAccountingProfileId.IsEmpty())
		{
			SessionConfig.UsageCostAccountingProfileId = TEXT("speech-usage-cost-accounting-v1");
		}
		if (!SessionConfig.UsageCostAccountingProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.UsageCostAccountingProfileDefinition =
				BuildDefaultSpeechUsageCostAccountingProfile(
					SessionConfig.UsageCostAccountingProfileId
				);
		}
		SessionConfig.UsageCostAccountingProfileId =
			SessionConfig.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId;

		const FHyperTwistSpeechProviderProfile EffectiveProfile =
			SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderProfileDefinition
				: BuildDefaultHttpSpeechProviderProfile(
					TEXT("Local HTTP Speech Sidecar"),
					TEXT("http://127.0.0.1:8766")
				);
		const FString EffectiveServiceLaneId =
			!SessionConfig.ProviderRouteDecision.SelectedServiceLaneId.IsEmpty()
				? SessionConfig.ProviderRouteDecision.SelectedServiceLaneId
				: (!SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
					? SessionConfig.OrchestrationProfile.ServiceLaneId
					: TEXT("speech/python-service"));
		const bool bNeedsUsageTemplate =
			!SessionConfig.UsageEventTemplate.IsStructurallyValid()
			|| SessionConfig.UsageEventTemplate.UsageCostAccountingProfileId
				!= SessionConfig.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId
			|| SessionConfig.UsageEventTemplate.ProviderProfileId != EffectiveProfile.ProviderProfileId
			|| SessionConfig.UsageEventTemplate.ServiceLaneId != EffectiveServiceLaneId;
		if (bNeedsUsageTemplate)
		{
			SessionConfig.UsageEventTemplate = BuildDefaultSpeechUsageEvent(
				SessionConfig.UsageCostAccountingProfileDefinition,
				EffectiveProfile,
				EffectiveServiceLaneId,
				TEXT("bounded-session-usage-summary"),
				TEXT("current-session"),
				TEXT("session-config-template"),
				0.0f,
				0.0f,
				false,
				true
			);
		}
		const bool bNeedsCostTemplate =
			!SessionConfig.CostEventTemplate.IsStructurallyValid()
			|| SessionConfig.CostEventTemplate.UsageCostAccountingProfileId
				!= SessionConfig.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId
			|| SessionConfig.CostEventTemplate.ProviderProfileId != EffectiveProfile.ProviderProfileId
			|| SessionConfig.CostEventTemplate.ServiceLaneId != EffectiveServiceLaneId;
		if (bNeedsCostTemplate)
		{
			SessionConfig.CostEventTemplate = BuildDefaultSpeechCostEvent(
				SessionConfig.UsageCostAccountingProfileDefinition,
				EffectiveProfile,
				EffectiveServiceLaneId,
				TEXT("bounded-session-cost-summary"),
				TEXT("current-session"),
				0.0f,
				0.0f,
				true,
				false
			);
		}
		if (SessionConfig.UsageCostDashboardShellProfileId.IsEmpty()
			&& SessionConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.UsageCostDashboardShellProfileId =
				SessionConfig.UsageCostDashboardShellProfileDefinition.DashboardShellProfileId;
		}
		if (SessionConfig.UsageCostDashboardShellProfileId.IsEmpty())
		{
			SessionConfig.UsageCostDashboardShellProfileId =
				TEXT("speech-provider-usage-cost-dashboard-shell-v1");
		}
		if (!SessionConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.UsageCostDashboardShellProfileDefinition =
				BuildDefaultSpeechUsageCostDashboardShellProfile(
					SessionConfig.UsageCostDashboardShellProfileId
				);
		}
		SessionConfig.UsageCostDashboardShellProfileId =
			SessionConfig.UsageCostDashboardShellProfileDefinition.DashboardShellProfileId;
		if (SessionConfig.UsageCostHistoryExportShellProfileId.IsEmpty()
			&& SessionConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.UsageCostHistoryExportShellProfileId =
				SessionConfig.UsageCostHistoryExportShellProfileDefinition.HistoryExportShellProfileId;
		}
		if (SessionConfig.UsageCostHistoryExportShellProfileId.IsEmpty())
		{
			SessionConfig.UsageCostHistoryExportShellProfileId =
				TEXT("speech-provider-usage-cost-history-export-shell-v1");
		}
		if (!SessionConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.UsageCostHistoryExportShellProfileDefinition =
				BuildDefaultSpeechUsageCostHistoryExportShellProfile(
					SessionConfig.UsageCostHistoryExportShellProfileId
				);
		}
		SessionConfig.UsageCostHistoryExportShellProfileId =
			SessionConfig.UsageCostHistoryExportShellProfileDefinition.HistoryExportShellProfileId;
		if (SessionConfig.ProviderReceiptReviewShellProfileId.IsEmpty()
			&& SessionConfig.ProviderReceiptReviewShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderReceiptReviewShellProfileId =
				SessionConfig.ProviderReceiptReviewShellProfileDefinition.ReceiptReviewShellProfileId;
		}
		if (SessionConfig.ProviderReceiptReviewShellProfileId.IsEmpty())
		{
			SessionConfig.ProviderReceiptReviewShellProfileId =
				TEXT("speech-provider-receipt-review-shell-v1");
		}
		if (!SessionConfig.ProviderReceiptReviewShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderReceiptReviewShellProfileDefinition =
				BuildDefaultSpeechProviderReceiptReviewShellProfile(
					SessionConfig.ProviderReceiptReviewShellProfileId
				);
		}
		SessionConfig.ProviderReceiptReviewShellProfileId =
			SessionConfig.ProviderReceiptReviewShellProfileDefinition.ReceiptReviewShellProfileId;
		if (SessionConfig.ProviderBillingSettlementShellProfileId.IsEmpty()
			&& SessionConfig.ProviderBillingSettlementShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderBillingSettlementShellProfileId =
				SessionConfig.ProviderBillingSettlementShellProfileDefinition.BillingSettlementShellProfileId;
		}
		if (SessionConfig.ProviderBillingSettlementShellProfileId.IsEmpty())
		{
			SessionConfig.ProviderBillingSettlementShellProfileId =
				TEXT("speech-provider-billing-settlement-shell-v1");
		}
		if (!SessionConfig.ProviderBillingSettlementShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderBillingSettlementShellProfileDefinition =
				BuildDefaultSpeechProviderBillingSettlementShellProfile(
					SessionConfig.ProviderBillingSettlementShellProfileId
				);
		}
		SessionConfig.ProviderBillingSettlementShellProfileId =
			SessionConfig.ProviderBillingSettlementShellProfileDefinition.BillingSettlementShellProfileId;
		if (SessionConfig.ProviderSettlementExceptionShellProfileId.IsEmpty()
			&& SessionConfig.ProviderSettlementExceptionShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderSettlementExceptionShellProfileId =
				SessionConfig.ProviderSettlementExceptionShellProfileDefinition
					.SettlementExceptionShellProfileId;
		}
		if (SessionConfig.ProviderSettlementExceptionShellProfileId.IsEmpty())
		{
			SessionConfig.ProviderSettlementExceptionShellProfileId =
				TEXT("speech-provider-settlement-exception-shell-v1");
		}
		if (!SessionConfig.ProviderSettlementExceptionShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ProviderSettlementExceptionShellProfileDefinition =
				BuildDefaultSpeechProviderSettlementExceptionShellProfile(
					SessionConfig.ProviderSettlementExceptionShellProfileId
				);
		}
		SessionConfig.ProviderSettlementExceptionShellProfileId =
			SessionConfig.ProviderSettlementExceptionShellProfileDefinition
				.SettlementExceptionShellProfileId;
	}

	void ApplySpeechProviderProfileHealthDefaults(
		FHyperTwistSpeechServiceHealth& Health,
		const bool bUseProviderBackedClient
	)
	{
		if (Health.ProviderProfileId.IsEmpty()
			&& Health.ProviderProfileDefinition.IsStructurallyValid())
		{
			Health.ProviderProfileId = Health.ProviderProfileDefinition.ProviderProfileId;
		}
		if (Health.ProviderProfileId.IsEmpty())
		{
			Health.ProviderProfileId = bUseProviderBackedClient
				? TEXT("speech-provider/local-http-sidecar-profile-v1")
				: TEXT("speech-provider/mock-offline-profile-v1");
		}
		if (!Health.ProviderProfileDefinition.IsStructurallyValid())
		{
			Health.ProviderProfileDefinition = bUseProviderBackedClient
				? BuildDefaultHttpSpeechProviderProfile(
					Health.ProviderLabel,
					Health.ServiceEndpoint
				)
				: BuildDefaultMockSpeechProviderProfile();
		}
		Health.ProviderProfileId = Health.ProviderProfileDefinition.ProviderProfileId;
		if (Health.ByokCustodyProfileId.IsEmpty()
			&& Health.ByokCustodyProfileDefinition.IsStructurallyValid())
		{
			Health.ByokCustodyProfileId = Health.ByokCustodyProfileDefinition.ByokCustodyProfileId;
		}
		if (Health.ByokCustodyProfileId.IsEmpty())
		{
			Health.ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1");
		}
		if (!Health.ByokCustodyProfileDefinition.IsStructurallyValid())
		{
			Health.ByokCustodyProfileDefinition =
				BuildDefaultSpeechByokCustodyProfile(Health.ByokCustodyProfileId);
		}
		Health.ByokCustodyProfileId = Health.ByokCustodyProfileDefinition.ByokCustodyProfileId;
		Health.Capabilities.AddUnique(TEXT("providerProfileCustody"));
		Health.Capabilities.AddUnique(TEXT("byokCustody"));
		Health.Capabilities.AddUnique(TEXT("openAiCompatibleCustomEndpointProfile"));
		Health.Capabilities.AddUnique(TEXT("userLabeledByokProfiles"));
	}

	void ApplySpeechProviderRoutingHealthDefaults(
		FHyperTwistSpeechServiceHealth& Health,
		const FHyperTwistSpeechSessionConfig* SessionConfig,
		const bool bUseProviderBackedClient,
		const FString& LastError
	)
	{
		if (Health.ProviderRoutingPolicyId.IsEmpty()
			&& Health.ProviderRoutingPolicyDefinition.IsStructurallyValid())
		{
			Health.ProviderRoutingPolicyId =
				Health.ProviderRoutingPolicyDefinition.ProviderRoutingPolicyId;
		}
		if (Health.ProviderRoutingPolicyId.IsEmpty())
		{
			Health.ProviderRoutingPolicyId = bUseProviderBackedClient
				? TEXT("speech-provider-routing/provider-backed-sidecar-first-v1")
				: TEXT("speech-provider-routing/local-offline-mock-first-v1");
		}
		if (!Health.ProviderRoutingPolicyDefinition.IsStructurallyValid())
		{
			Health.ProviderRoutingPolicyDefinition = bUseProviderBackedClient
				? BuildDefaultProviderBackedSpeechProviderRoutingPolicy()
				: BuildDefaultMockSpeechProviderRoutingPolicy();
		}
		Health.ProviderRoutingPolicyId = Health.ProviderRoutingPolicyDefinition.ProviderRoutingPolicyId;

		const FHyperTwistSpeechProviderProfile EffectiveProfile =
			Health.ProviderProfileDefinition.IsStructurallyValid()
				? Health.ProviderProfileDefinition
				: (SessionConfig != nullptr && SessionConfig->ProviderProfileDefinition.IsStructurallyValid()
					? SessionConfig->ProviderProfileDefinition
					: (bUseProviderBackedClient
						? BuildDefaultHttpSpeechProviderProfile(
							Health.ProviderLabel,
							Health.ServiceEndpoint
						)
						: BuildDefaultMockSpeechProviderProfile()));
		const FString EffectiveRouteError = !LastError.IsEmpty() ? LastError : Health.LastError;
		const FString SelectedServiceLaneId =
			SessionConfig != nullptr
			&& !SessionConfig->OrchestrationProfile.ServiceLaneId.IsEmpty()
				? SessionConfig->OrchestrationProfile.ServiceLaneId
				: TEXT("speech/python-service");

		FString RouteStateId;
		FString DecisionReason;
		FString FailureReason;
		bool bRouteReady = true;
		bool bUsedFallbackHealthPosture = false;

		if (!EffectiveProfile.bEnabled)
		{
			RouteStateId = TEXT("route-disabled");
			DecisionReason = TEXT("selected-provider-profile-disabled");
			FailureReason = TEXT("selected-provider-profile-disabled");
			bRouteReady = false;
		}
		else if (!bUseProviderBackedClient)
		{
			if (!Health.bReady && !EffectiveRouteError.IsEmpty())
			{
				RouteStateId = TEXT("route-health-degraded");
				DecisionReason = TEXT("mock-verification-route-health-degraded");
				FailureReason = EffectiveRouteError;
				bRouteReady = false;
			}
			else
			{
				RouteStateId = TEXT("route-ready");
				DecisionReason = TEXT("mock-verification-route-selected");
			}
		}
		else if (EffectiveRouteError == TEXT("no-active-training-run"))
		{
			RouteStateId = TEXT("route-idle");
			DecisionReason = TEXT("provider-backed-route-idle");
			FailureReason = EffectiveRouteError;
			bRouteReady = false;
			bUsedFallbackHealthPosture = true;
		}
		else if (EffectiveProfile.EndpointBaseUrl.IsEmpty()
			|| EffectiveRouteError == TEXT("service-base-url-missing"))
		{
			RouteStateId = TEXT("route-awaiting-endpoint");
			DecisionReason = TEXT("provider-backed-sidecar-route-unavailable");
			FailureReason = TEXT("service-base-url-missing");
			bRouteReady = false;
			bUsedFallbackHealthPosture = true;
		}
		else if (!Health.bReady || !EffectiveRouteError.IsEmpty())
		{
			RouteStateId = TEXT("route-health-degraded");
			DecisionReason = TEXT("provider-backed-sidecar-health-degraded");
			FailureReason = !EffectiveRouteError.IsEmpty()
				? EffectiveRouteError
				: TEXT("provider-route-unready");
			bRouteReady = false;
			bUsedFallbackHealthPosture = true;
		}
		else
		{
			RouteStateId = TEXT("route-ready");
			DecisionReason = TEXT("provider-backed-sidecar-route-selected");
		}

		Health.ProviderRouteDecision = BuildSpeechProviderRouteDecision(
			Health.ProviderRoutingPolicyDefinition,
			EffectiveProfile,
			SelectedServiceLaneId,
			TEXT("service-health-refresh"),
			RouteStateId,
			DecisionReason,
			FailureReason,
			bUseProviderBackedClient,
			bUseProviderBackedClient,
			bUsedFallbackHealthPosture,
			bRouteReady
		);
		Health.Capabilities.AddUnique(TEXT("providerRoutingPolicy"));
		Health.Capabilities.AddUnique(TEXT("providerRouteSelection"));
		Health.Capabilities.AddUnique(TEXT("workflowPolicyState"));
	}

	void ApplySpeechPayloadCustodyHealthDefaults(FHyperTwistSpeechServiceHealth& Health)
	{
		if (Health.PayloadCustodyProfileId.IsEmpty())
		{
			Health.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1");
		}
		if (!Health.PayloadCustodyProfileDefinition.IsStructurallyValid())
		{
			Health.PayloadCustodyProfileDefinition =
				BuildDefaultSpeechPayloadCustodyProfile(Health.PayloadCustodyProfileId);
		}
		if (Health.SupportedModelPayloadIds.Num() <= 0)
		{
			Health.SupportedModelPayloadIds = {
				TEXT("speech-model/whisper.cpp/base.en"),
				TEXT("speech-vad/whisper.cpp/silero-v6.2.0")
			};
		}
		if (Health.SupportedModelPayloads.Num() <= 0)
		{
			Health.SupportedModelPayloads = BuildDefaultSpeechModelPayloads();
		}
		Health.Capabilities.AddUnique(TEXT("downloadableModelPayloadCustody"));
		Health.Capabilities.AddUnique(TEXT("payloadIntegrityReview"));
	}

	void ApplySpeechUsageCostHealthDefaults(
		FHyperTwistSpeechServiceHealth& Health,
		const FHyperTwistSpeechSessionConfig* SessionConfig,
		const FString& LastError
	)
	{
		if (Health.UsageCostAccountingProfileId.IsEmpty()
			&& Health.UsageCostAccountingProfileDefinition.IsStructurallyValid())
		{
			Health.UsageCostAccountingProfileId =
				Health.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId;
		}
		if (Health.UsageCostAccountingProfileId.IsEmpty())
		{
			Health.UsageCostAccountingProfileId = TEXT("speech-usage-cost-accounting-v1");
		}
		if (!Health.UsageCostAccountingProfileDefinition.IsStructurallyValid())
		{
			Health.UsageCostAccountingProfileDefinition =
				BuildDefaultSpeechUsageCostAccountingProfile(
					Health.UsageCostAccountingProfileId
				);
		}
		Health.UsageCostAccountingProfileId =
			Health.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId;

		const FHyperTwistSpeechProviderProfile EffectiveProfile =
			Health.ProviderProfileDefinition.IsStructurallyValid()
				? Health.ProviderProfileDefinition
				: (SessionConfig != nullptr && SessionConfig->ProviderProfileDefinition.IsStructurallyValid()
					? SessionConfig->ProviderProfileDefinition
					: BuildDefaultMockSpeechProviderProfile());
		const FString EffectiveServiceLaneId =
			Health.ProviderRouteDecision.IsStructurallyValid()
			&& !Health.ProviderRouteDecision.SelectedServiceLaneId.IsEmpty()
				? Health.ProviderRouteDecision.SelectedServiceLaneId
				: (SessionConfig != nullptr
					&& !SessionConfig->OrchestrationProfile.ServiceLaneId.IsEmpty()
						? SessionConfig->OrchestrationProfile.ServiceLaneId
						: TEXT("speech/python-service"));
		const FString EffectiveError = !LastError.IsEmpty()
			? LastError
			: (!Health.LastError.IsEmpty()
				? Health.LastError
				: Health.ProviderRouteDecision.FailureReason);
		const bool bRouteReady = !Health.ProviderRouteDecision.IsStructurallyValid()
			? Health.bReady
			: Health.ProviderRouteDecision.bRouteReady;
		const bool bUseHealthPostureEvent = !EffectiveError.IsEmpty() || !bRouteReady || !Health.bReady;
		const FString ExpectedUsageEventKind = bUseHealthPostureEvent
			? TEXT("provider-route-health-posture")
			: TEXT("bounded-session-usage-summary");
		const bool bNeedsUsageEvent =
			!Health.LatestUsageEvent.IsStructurallyValid()
			|| Health.LatestUsageEvent.UsageCostAccountingProfileId
				!= Health.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId
			|| Health.LatestUsageEvent.ProviderProfileId != EffectiveProfile.ProviderProfileId
			|| Health.LatestUsageEvent.ServiceLaneId != EffectiveServiceLaneId
			|| Health.LatestUsageEvent.EventKind != ExpectedUsageEventKind
			|| (bUseHealthPostureEvent && Health.LatestUsageEvent.RawEventReferenceId != EffectiveError);
		if (bNeedsUsageEvent)
		{
			Health.LatestUsageEvent = BuildDefaultSpeechUsageEvent(
				Health.UsageCostAccountingProfileDefinition,
				EffectiveProfile,
				EffectiveServiceLaneId,
				ExpectedUsageEventKind,
				TEXT("service-health-window"),
				bUseHealthPostureEvent
					? EffectiveError
					: TEXT("service-health-refresh"),
				bUseHealthPostureEvent ? 0.0f : 0.75f,
				0.0f,
				false,
				true
			);
		}
		const FString ExpectedCostEventKind = bUseHealthPostureEvent
			? TEXT("provider-route-health-posture")
			: TEXT("bounded-session-cost-summary");
		const bool bNeedsCostEvent =
			!Health.LatestCostEvent.IsStructurallyValid()
			|| Health.LatestCostEvent.UsageCostAccountingProfileId
				!= Health.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId
			|| Health.LatestCostEvent.ProviderProfileId != EffectiveProfile.ProviderProfileId
			|| Health.LatestCostEvent.ServiceLaneId != EffectiveServiceLaneId
			|| Health.LatestCostEvent.EventKind != ExpectedCostEventKind;
		if (bNeedsCostEvent)
		{
			Health.LatestCostEvent = BuildDefaultSpeechCostEvent(
				Health.UsageCostAccountingProfileDefinition,
				EffectiveProfile,
				EffectiveServiceLaneId,
				ExpectedCostEventKind,
				TEXT("service-health-window"),
				bUseHealthPostureEvent ? 0.0f : 0.01f,
				0.0f,
				true,
				false
			);
		}
		const FString ExpectedQuotaReason = bUseHealthPostureEvent
			? (!EffectiveError.IsEmpty() ? EffectiveError : TEXT("provider-route-unready"))
			: TEXT("within-budget");
		const bool bNeedsQuotaState =
			!Health.QuotaRateLimitState.IsStructurallyValid()
			|| Health.QuotaRateLimitState.UsageCostAccountingProfileId
				!= Health.UsageCostAccountingProfileDefinition.UsageCostAccountingProfileId
			|| Health.QuotaRateLimitState.ProviderProfileId != EffectiveProfile.ProviderProfileId
			|| Health.QuotaRateLimitState.ServiceLaneId != EffectiveServiceLaneId
			|| Health.QuotaRateLimitState.StateReason != ExpectedQuotaReason
			|| Health.QuotaRateLimitState.bQuotaKnown == bUseHealthPostureEvent;
		if (bNeedsQuotaState)
		{
			Health.QuotaRateLimitState = BuildDefaultSpeechQuotaRateLimitState(
				Health.UsageCostAccountingProfileDefinition,
				EffectiveProfile,
				EffectiveServiceLaneId,
				ExpectedQuotaReason,
				!bUseHealthPostureEvent,
				false,
				false,
				bUseHealthPostureEvent ? 0 : 60,
				bUseHealthPostureEvent ? 0 : 3600,
				bUseHealthPostureEvent ? 0.0f : 25.0f
			);
		}
		Health.Capabilities.AddUnique(TEXT("normalizedUsageEvents"));
		Health.Capabilities.AddUnique(TEXT("normalizedCostEvents"));
		Health.Capabilities.AddUnique(TEXT("quotaRateLimitState"));
		Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
		Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
		Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
		Health.Capabilities.AddUnique(TEXT("providerUsageCostHistoryShell"));
		Health.Capabilities.AddUnique(TEXT("providerUsageCostExportPreview"));
		Health.Capabilities.AddUnique(TEXT("providerUsageCostSummaryCopy"));
		Health.Capabilities.AddUnique(TEXT("providerReceiptReviewShell"));
		Health.Capabilities.AddUnique(TEXT("providerPostedChargeInspection"));
		Health.Capabilities.AddUnique(TEXT("providerChargeVarianceReview"));
		Health.Capabilities.AddUnique(TEXT("providerBillingSettlementShell"));
		Health.Capabilities.AddUnique(TEXT("providerInvoiceReconciliation"));
		Health.Capabilities.AddUnique(TEXT("providerSettlementReadinessReview"));
		Health.Capabilities.AddUnique(TEXT("providerSettlementExceptionShell"));
		Health.Capabilities.AddUnique(TEXT("providerExternalPortalHandoff"));
		Health.Capabilities.AddUnique(TEXT("providerSettlementExceptionReview"));
		Health.Capabilities.AddUnique(TEXT("devicePermissionWorkflow"));
		Health.Capabilities.AddUnique(TEXT("devicePermissionSettingsHandoff"));
		Health.Capabilities.AddUnique(TEXT("devicePermissionRecheck"));
	}

	void ApplySpeechNativeCaptureRouteHealthDefaults(FHyperTwistSpeechServiceHealth& Health)
	{
		Health.Capabilities.AddUnique(TEXT("nativeCaptureRouteWorkflow"));
		Health.Capabilities.AddUnique(TEXT("nativeCaptureRouteWorkflowShell"));
		Health.Capabilities.AddUnique(TEXT("captureRoutePreparationControl"));
		Health.Capabilities.AddUnique(TEXT("captureRouteOwnershipAssessment"));
		Health.Capabilities.AddUnique(TEXT("captureRouteOwnershipSummaryCard"));
		Health.Capabilities.AddUnique(TEXT("captureRoutePreparationCard"));
		Health.Capabilities.AddUnique(TEXT("captureRouteSessionReopenCard"));
		Health.Capabilities.AddUnique(TEXT("reopenSpeechSession"));
	}

	void ApplySpeechExternalDictationHealthDefaults(FHyperTwistSpeechServiceHealth& Health)
	{
		Health.Capabilities.AddUnique(TEXT("externalDictationShell"));
		Health.Capabilities.AddUnique(TEXT("speechTranscriptHistoryShell"));
		Health.Capabilities.AddUnique(TEXT("speechOutputRoutingShell"));
		Health.Capabilities.AddUnique(TEXT("speechTranscriptPostProcessOverlay"));
		Health.Capabilities.AddUnique(TEXT("speechGlobalHotkeyShell"));
		Health.Capabilities.AddUnique(TEXT("speechDeviceSelectionShell"));
		Health.Capabilities.AddUnique(TEXT("speechMuteWhileRecordingShell"));
		Health.Capabilities.AddUnique(TEXT("speechMicrophoneModeShell"));
		Health.Capabilities.AddUnique(TEXT("speechLocalModelCatalogShell"));
		Health.Capabilities.AddUnique(TEXT("speechModelIntegrityShell"));
		Health.Capabilities.AddUnique(TEXT("speechModelUnloadPolicyShell"));
	}

bool IsSpeechPermissionError(const FString& ErrorText)
{
	const FString NormalizedError = ErrorText.ToLower();
	return NormalizedError.Contains(TEXT("permission"))
		|| NormalizedError.Contains(TEXT("not-allowed"))
		|| NormalizedError.Contains(TEXT("access-denied"));
}

bool IsSpeechPermissionSettingsError(const FString& ErrorText)
{
	const FString NormalizedError = ErrorText.ToLower();
	return IsSpeechPermissionError(ErrorText)
		&& (NormalizedError.Contains(TEXT("denied"))
			|| NormalizedError.Contains(TEXT("blocked"))
			|| NormalizedError.Contains(TEXT("settings"))
			|| NormalizedError.Contains(TEXT("privacy")));
}

bool IsSpeechPermissionRecheckError(const FString& ErrorText)
{
	const FString NormalizedError = ErrorText.ToLower();
	return IsSpeechPermissionError(ErrorText)
		&& (NormalizedError.Contains(TEXT("recheck"))
			|| NormalizedError.Contains(TEXT("retry-permission"))
			|| NormalizedError.Contains(TEXT("verify-permission"))
			|| NormalizedError.Contains(TEXT("pending")));
}

	bool IsSpeechRouteError(const FString& ErrorText)
	{
		const FString NormalizedError = ErrorText.ToLower();
		return NormalizedError.Contains(TEXT("speech-client"))
			|| NormalizedError.Contains(TEXT("service-base-url"))
			|| NormalizedError.Contains(TEXT("request-"))
			|| NormalizedError.Contains(TEXT("response-missing"))
			|| NormalizedError.Contains(TEXT("invalid-provider-response"))
			|| NormalizedError.Contains(TEXT("http-"))
			|| NormalizedError.Contains(TEXT("session-not-open"));
	}

	void AddSpeechMicrophoneShellIssue(
		FHyperTwistSpeechMicrophoneShellState& ShellState,
		const FHyperTwistSpeechMicrophoneShellIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechMicrophoneShellPosture(
		const FHyperTwistSpeechMicrophoneShellProfile& Profile,
		const FHyperTwistSpeechServiceHealth& ServiceHealth,
		const FString& LastError,
		const bool bSessionOpen,
		FHyperTwistSpeechMicrophoneShellState& ShellState
	)
	{
		ShellState.PermissionStateId = TEXT("permission-granted");
		ShellState.CaptureRouteStateId = bSessionOpen ? TEXT("route-ready") : TEXT("route-closed");
		ShellState.StatusLine = bSessionOpen
			? TEXT("Microphone route ready for coach commands.")
			: TEXT("Microphone session closed.");
		ShellState.DetailLine = bSessionOpen
			? TEXT("Live capture is armed for the next bounded coach command.")
			: TEXT("Reopen the companion speech session when microphone capture is needed again.");
		ShellState.bMicrophonePermissionGranted = true;
		ShellState.bCaptureRouteReady = bSessionOpen && ServiceHealth.bReady;
		ShellState.bPermissionPromptVisible = false;
		ShellState.bPermissionRequestVisible = false;
		ShellState.bCaptureRouteRetryVisible = false;
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechMicrophoneShellIssue();
		ShellState.ActiveIssueCount = 0;

		if (!bSessionOpen)
		{
			ShellState.bCaptureActive = false;
			ShellState.bAwaitingSpeech = false;
			ShellState.bTranscriptionInFlight = false;
		}

		const FString RouteError = !LastError.IsEmpty() ? LastError : ServiceHealth.LastError;
		ShellState.LastRouteError = RouteError;
		if (LastError == TEXT("no-active-training-run"))
		{
			ShellState.CaptureRouteStateId = TEXT("route-idle");
			ShellState.StatusLine = TEXT("Start a training run before microphone capture opens.");
			ShellState.DetailLine =
				TEXT("The shell is available, but no active training run currently owns the speech route.");
			ShellState.bCaptureRouteReady = false;
		}
		else if (IsSpeechPermissionError(RouteError))
		{
			FHyperTwistSpeechMicrophoneShellIssue Issue;
			Issue.IssueId = TEXT("microphone-permission-required");
			Issue.IssueKind = TEXT("permission-required");
			Issue.StatusLine = TEXT("Microphone permission is required before capture can start.");
			Issue.DetailLine =
				TEXT("Use the first-party permission workflow to request access, review system settings, and recheck before reopening capture. Native OS grant execution remains outside this packet.");
			Issue.RecommendedActionId = Profile.PermissionRequestActionId;
			AddSpeechMicrophoneShellIssue(ShellState, Issue);

			ShellState.PermissionStateId = TEXT("permission-required");
			ShellState.CaptureRouteStateId = TEXT("route-waiting-for-permission");
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.bMicrophonePermissionGranted = false;
			ShellState.bCaptureRouteReady = false;
			ShellState.bCaptureActive = false;
			ShellState.bAwaitingSpeech = false;
			ShellState.bTranscriptionInFlight = false;
			ShellState.bPermissionPromptVisible = Profile.bSupportsPermissionRequest;
			ShellState.bPermissionRequestVisible = Profile.bSupportsPermissionRequest;
		}
		else if ((IsSpeechRouteError(RouteError) && LastError != TEXT("no-active-training-run")) || (bSessionOpen && !ServiceHealth.bReady))
		{
			FHyperTwistSpeechMicrophoneShellIssue Issue;
			Issue.IssueId = TEXT("capture-route-unavailable");
			Issue.IssueKind = TEXT("capture-route-unavailable");
			Issue.StatusLine = TEXT("Capture route unavailable.");
			Issue.DetailLine = RouteError.IsEmpty()
				? TEXT("The speech route is not ready yet. Retry once the sidecar or device route reports healthy again.")
				: FString::Printf(
					TEXT("The speech route reported '%s'. Retry once the sidecar or device route reports healthy again."),
					*RouteError
				);
			Issue.RecommendedActionId = Profile.CaptureRouteRetryActionId;
			AddSpeechMicrophoneShellIssue(ShellState, Issue);

			ShellState.CaptureRouteStateId = TEXT("route-retry-required");
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.bCaptureRouteReady = false;
			ShellState.bCaptureActive = false;
			ShellState.bAwaitingSpeech = false;
			ShellState.bTranscriptionInFlight = false;
			ShellState.bCaptureRouteRetryVisible = Profile.bSupportsCaptureRouteRetry;
		}

		if (ShellState.bPermissionRequestVisible)
		{
			ShellState.AvailableActionIds.AddUnique(Profile.PermissionRequestActionId);
		}
		if (ShellState.bCaptureRouteRetryVisible)
		{
			ShellState.AvailableActionIds.AddUnique(Profile.CaptureRouteRetryActionId);
		}

		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechMicrophoneShellState(FHyperTwistTrainingCompanionSpeechSessionState& SessionState)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		if (EffectiveConfig.ListeningContractId.IsEmpty())
		{
			EffectiveConfig.ListeningContractId = TEXT("listening-threshold-lifecycle");
		}
		if (EffectiveConfig.InputRouteId.IsEmpty())
		{
			EffectiveConfig.InputRouteId = TEXT("queue/listening");
		}
		if (EffectiveConfig.LanguageMode.IsEmpty())
		{
			EffectiveConfig.LanguageMode = TEXT("auto");
		}
		if (EffectiveConfig.MicrophoneShellProfileId.IsEmpty())
		{
			EffectiveConfig.MicrophoneShellProfileId = TEXT("coach-command-microphone-shell-v1");
		}
		if (!EffectiveConfig.bEnableVad)
		{
			EffectiveConfig.bEnableVad = true;
		}
		const FHyperTwistSpeechMicrophoneShellProfile Profile =
			EffectiveConfig.MicrophoneShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.MicrophoneShellProfileDefinition
				: BuildDefaultCoachCommandMicrophoneShellProfile(
					!EffectiveConfig.MicrophoneShellProfileId.IsEmpty()
						? EffectiveConfig.MicrophoneShellProfileId
						: TEXT("coach-command-microphone-shell-v1")
				);

		if (!SessionState.MicrophoneShellState.IsStructurallyValid())
		{
			SessionState.MicrophoneShellState =
				BuildCoachCommandMicrophoneShellState(
					EffectiveConfig,
					&SessionState,
					SessionState.bSessionOpen
				);
		}

		FHyperTwistSpeechMicrophoneShellState& ShellState = SessionState.MicrophoneShellState;
		ShellState.MicrophoneShellProfileId = Profile.MicrophoneShellProfileId;
		ShellState.CaptureMode = Profile.CaptureMode;
		ShellState.ListeningContractId = !EffectiveConfig.ListeningContractId.IsEmpty()
			? EffectiveConfig.ListeningContractId
			: TEXT("listening-threshold-lifecycle");
		ShellState.InputRouteId = !EffectiveConfig.InputRouteId.IsEmpty()
			? EffectiveConfig.InputRouteId
			: TEXT("queue/listening");
		if (ShellState.LastLanguageCode.IsEmpty())
		{
			ShellState.LastLanguageCode =
				EffectiveConfig.LanguageMode.IsEmpty()
				|| EffectiveConfig.LanguageMode.Equals(TEXT("auto"), ESearchCase::IgnoreCase)
					? TEXT("en")
					: EffectiveConfig.LanguageMode;
		}
		ShellState.StepWindowMs = Profile.StepWindowMs;
		ShellState.CaptureWindowMs = Profile.CaptureWindowMs;
		ShellState.KeepWindowMs = Profile.KeepWindowMs;
		ShellState.VadThreshold = Profile.VadThreshold;
		ShellState.bSessionOpen = SessionState.bSessionOpen;
		ShellState.bVadArmed = EffectiveConfig.bEnableVad;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechMicrophoneShellPosture(
			Profile,
			SessionState.ServiceHealth,
			SessionState.LastError,
			SessionState.bSessionOpen,
			ShellState
		);
	}

	void AddSpeechDevicePermissionWorkflowIssue(
		FHyperTwistSpeechDevicePermissionWorkflowState& WorkflowState,
		const FHyperTwistSpeechDevicePermissionWorkflowIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		WorkflowState.Issues.Add(Issue);
		if (!WorkflowState.ActiveIssue.IsStructurallyValid())
		{
			WorkflowState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechDevicePermissionWorkflowPosture(
		const FHyperTwistSpeechDevicePermissionWorkflowProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechDevicePermissionWorkflowState& WorkflowState
	)
	{
		const FString PermissionError = !SessionState.LastError.IsEmpty()
			? SessionState.LastError
			: SessionState.ServiceHealth.LastError;

		WorkflowState.PermissionStateId = SessionState.MicrophoneShellState.IsStructurallyValid()
			? SessionState.MicrophoneShellState.PermissionStateId
			: TEXT("permission-granted");
		WorkflowState.WorkflowStateId = TEXT("permission-workflow-cleared");
		WorkflowState.LatestSourceKind = TEXT("permission-state-granted");
		WorkflowState.StatusLine = SessionState.bSessionOpen
			? TEXT("Microphone permission already granted.")
			: TEXT("Permission workflow ready when the speech shell opens.");
		WorkflowState.DetailLine = SessionState.bSessionOpen
			? TEXT("The first-party permission workflow is clear for the bounded speech shell.")
			: TEXT("Open the companion speech session to evaluate live permission posture.");
		WorkflowState.LastPermissionError = PermissionError;
		WorkflowState.WorkflowEntryCount = 0;
		WorkflowState.PermissionRequestEntryCount = 0;
		WorkflowState.SettingsHandoffEntryCount = 0;
		WorkflowState.PermissionRecheckEntryCount = 0;
		WorkflowState.bPermissionGranted = true;
		WorkflowState.bWorkflowSummaryReady = true;
		WorkflowState.bPermissionWorkflowReady = true;
		WorkflowState.bSettingsReviewRecommended = false;
		WorkflowState.bPermissionRequestVisible = false;
		WorkflowState.bSettingsHandoffVisible = false;
		WorkflowState.bPermissionRecheckVisible = false;
		WorkflowState.Entries.Reset();
		WorkflowState.Issues.Reset();
		WorkflowState.ActiveIssue = FHyperTwistSpeechDevicePermissionWorkflowIssue();
		WorkflowState.ActiveIssueCount = 0;

		if (!PermissionError.IsEmpty() && IsSpeechPermissionError(PermissionError))
		{
			FHyperTwistSpeechDevicePermissionWorkflowEntry Entry;
			FHyperTwistSpeechDevicePermissionWorkflowIssue Issue;

			if (IsSpeechPermissionSettingsError(PermissionError))
			{
				Entry.EntryId = TEXT("device-permission-settings-review");
				Entry.SourceKind = TEXT("permission-settings-review-required");
				Entry.WorkflowStateId = TEXT("permission-settings-review-required");
				Entry.StatusLine =
					TEXT("Microphone permission must be reviewed in system settings.");
				Entry.DetailLine = FString::Printf(
					TEXT("The speech lane reported '%s'. Review the system privacy or permissions screen, then recheck before reopening capture."),
					*PermissionError
				);
				Entry.RecommendedActionId = Profile.OpenSettingsActionId;
				Entry.bRequiresSettingsHandoff = true;
				Entry.bRequiresPermissionRecheck = true;
				Entry.bPermissionGranted = false;

				Issue.IssueId = TEXT("device-permission-settings-review");
				Issue.IssueKind = TEXT("permission-settings-review-required");
				Issue.StatusLine = Entry.StatusLine;
				Issue.DetailLine = Entry.DetailLine;
				Issue.RecommendedActionId = Profile.OpenSettingsActionId;

				WorkflowState.SettingsHandoffEntryCount = 1;
				WorkflowState.PermissionRecheckEntryCount = 1;
				WorkflowState.bSettingsReviewRecommended = true;
				WorkflowState.bSettingsHandoffVisible = Profile.bSupportsSettingsHandoff;
				WorkflowState.bPermissionRecheckVisible = Profile.bSupportsPermissionRecheck;
			}
			else if (IsSpeechPermissionRecheckError(PermissionError))
			{
				Entry.EntryId = TEXT("device-permission-recheck");
				Entry.SourceKind = TEXT("permission-recheck-required");
				Entry.WorkflowStateId = TEXT("permission-recheck-required");
				Entry.StatusLine =
					TEXT("Microphone permission must be rechecked before capture resumes.");
				Entry.DetailLine = FString::Printf(
					TEXT("The speech lane reported '%s'. Recheck permission posture before reopening the bounded shell."),
					*PermissionError
				);
				Entry.RecommendedActionId = Profile.PermissionRecheckActionId;
				Entry.bRequiresPermissionRecheck = true;
				Entry.bPermissionGranted = false;

				Issue.IssueId = TEXT("device-permission-recheck");
				Issue.IssueKind = TEXT("permission-recheck-required");
				Issue.StatusLine = Entry.StatusLine;
				Issue.DetailLine = Entry.DetailLine;
				Issue.RecommendedActionId = Profile.PermissionRecheckActionId;

				WorkflowState.PermissionRecheckEntryCount = 1;
				WorkflowState.bPermissionRecheckVisible = Profile.bSupportsPermissionRecheck;
			}
			else
			{
				Entry.EntryId = TEXT("device-permission-request");
				Entry.SourceKind = TEXT("permission-request-required");
				Entry.WorkflowStateId = TEXT("permission-request-required");
				Entry.StatusLine =
					TEXT("Microphone permission must be requested before capture starts.");
				Entry.DetailLine = PermissionError.IsEmpty()
					? TEXT("Use the first-party permission workflow to request microphone access before reopening capture.")
					: FString::Printf(
						TEXT("The speech lane reported '%s'. Request microphone access before reopening capture."),
						*PermissionError
					);
				Entry.RecommendedActionId = Profile.PermissionRequestActionId;
				Entry.bPermissionGranted = false;

				Issue.IssueId = TEXT("device-permission-request");
				Issue.IssueKind = TEXT("permission-request-required");
				Issue.StatusLine = Entry.StatusLine;
				Issue.DetailLine = Entry.DetailLine;
				Issue.RecommendedActionId = Profile.PermissionRequestActionId;

				WorkflowState.PermissionRequestEntryCount = 1;
				WorkflowState.bPermissionRequestVisible = Profile.bSupportsPermissionRequest;
			}

			WorkflowState.Entries.Add(Entry);
			WorkflowState.WorkflowEntryCount = WorkflowState.Entries.Num();
			WorkflowState.WorkflowStateId = Entry.WorkflowStateId;
			WorkflowState.PermissionStateId = TEXT("permission-required");
			WorkflowState.LatestSourceKind = Entry.SourceKind;
			WorkflowState.StatusLine = Entry.StatusLine;
			WorkflowState.DetailLine = Entry.DetailLine;
			WorkflowState.bPermissionGranted = false;
			WorkflowState.bPermissionWorkflowReady = false;
			AddSpeechDevicePermissionWorkflowIssue(WorkflowState, Issue);
		}

		WorkflowState.ActiveIssueCount = WorkflowState.Issues.Num();
	}

	void SynchronizeSpeechDevicePermissionWorkflowState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		if (EffectiveConfig.DevicePermissionWorkflowProfileId.IsEmpty())
		{
			EffectiveConfig.DevicePermissionWorkflowProfileId =
				TEXT("speech-device-permission-workflow-v1");
		}
		const FHyperTwistSpeechDevicePermissionWorkflowProfile Profile =
			EffectiveConfig.DevicePermissionWorkflowProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.DevicePermissionWorkflowProfileDefinition
				: BuildDefaultSpeechDevicePermissionWorkflowProfile(
					!EffectiveConfig.DevicePermissionWorkflowProfileId.IsEmpty()
						? EffectiveConfig.DevicePermissionWorkflowProfileId
						: TEXT("speech-device-permission-workflow-v1")
				);

		if (!SessionState.DevicePermissionWorkflowState.IsStructurallyValid())
		{
			SessionState.DevicePermissionWorkflowState =
				BuildSpeechDevicePermissionWorkflowState(EffectiveConfig, &SessionState);
		}

		FHyperTwistSpeechDevicePermissionWorkflowState& WorkflowState =
			SessionState.DevicePermissionWorkflowState;
		WorkflowState.DevicePermissionWorkflowProfileId =
			Profile.DevicePermissionWorkflowProfileId;
		WorkflowState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			WorkflowState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechDevicePermissionWorkflowPosture(Profile, SessionState, WorkflowState);
	}

	void AddSpeechNativeCaptureRouteWorkflowIssue(
		FHyperTwistSpeechNativeCaptureRouteWorkflowState& WorkflowState,
		const FHyperTwistSpeechNativeCaptureRouteWorkflowIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		WorkflowState.Issues.Add(Issue);
		if (!WorkflowState.ActiveIssue.IsStructurallyValid())
		{
			WorkflowState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechNativeCaptureRouteWorkflowPosture(
		const FHyperTwistSpeechNativeCaptureRouteWorkflowProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechNativeCaptureRouteWorkflowState& WorkflowState
	)
	{
		const FHyperTwistSpeechMicrophoneShellState& ShellState = SessionState.MicrophoneShellState;
		const FHyperTwistSpeechDevicePermissionWorkflowState& PermissionWorkflowState =
			SessionState.DevicePermissionWorkflowState;
		const FHyperTwistSpeechProviderRouteDecision RouteDecision =
			SessionState.ServiceHealth.ProviderRouteDecision.IsStructurallyValid()
				? SessionState.ServiceHealth.ProviderRouteDecision
				: SessionState.SessionConfig.ProviderRouteDecision;
		const FString RouteError = !SessionState.LastError.IsEmpty()
			? SessionState.LastError
			: (!ShellState.LastRouteError.IsEmpty()
				? ShellState.LastRouteError
				: (!SessionState.ServiceHealth.LastError.IsEmpty()
					? SessionState.ServiceHealth.LastError
					: RouteDecision.FailureReason));

		WorkflowState.CaptureRouteStateId = !ShellState.CaptureRouteStateId.IsEmpty()
			? ShellState.CaptureRouteStateId
			: (!RouteDecision.RouteStateId.IsEmpty() ? RouteDecision.RouteStateId : TEXT("route-closed"));
		WorkflowState.PermissionStateId =
			PermissionWorkflowState.IsStructurallyValid() && !PermissionWorkflowState.PermissionStateId.IsEmpty()
				? PermissionWorkflowState.PermissionStateId
				: (!ShellState.PermissionStateId.IsEmpty()
					? ShellState.PermissionStateId
					: TEXT("permission-granted"));
		WorkflowState.ActiveProviderProfileId =
			RouteDecision.IsStructurallyValid() && !RouteDecision.SelectedProviderProfileId.IsEmpty()
				? RouteDecision.SelectedProviderProfileId
				: (!SessionState.SessionConfig.ProviderProfileId.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileId
					: TEXT("speech-provider/local-http-sidecar-profile-v1"));
		WorkflowState.ActiveServiceLaneId =
			RouteDecision.IsStructurallyValid() && !RouteDecision.SelectedServiceLaneId.IsEmpty()
				? RouteDecision.SelectedServiceLaneId
				: (!SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
					? SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId
					: TEXT("speech/python-service"));
		WorkflowState.LatestSourceKind = TEXT("capture-route-ready");
		WorkflowState.WorkflowStateId = TEXT("capture-route-workflow-cleared");
		WorkflowState.StatusLine = SessionState.bSessionOpen
			? TEXT("Native capture route owned for the active speech session.")
			: TEXT("Open the speech session before native capture-route ownership begins.");
		WorkflowState.DetailLine = SessionState.bSessionOpen
			? TEXT("The first-party native capture-route workflow is clear for the bounded speech lane.")
			: TEXT("The workflow stays first-party, but session-open control must happen before route ownership can be confirmed.");
		WorkflowState.LastRouteError = RouteError;
		WorkflowState.WorkflowEntryCount = 0;
		WorkflowState.PreparationEntryCount = 0;
		WorkflowState.RouteRetryEntryCount = 0;
		WorkflowState.SessionReopenEntryCount = 0;
		WorkflowState.PermissionDependencyEntryCount = 0;
		WorkflowState.bRouteOwnershipConfirmed = SessionState.bSessionOpen;
		WorkflowState.bWorkflowReady = SessionState.bSessionOpen;
		WorkflowState.bPreparationRequired = false;
		WorkflowState.bSessionOpenRequired = false;
		WorkflowState.bPermissionWorkflowBlocked = false;
		WorkflowState.bRouteInspectVisible = false;
		WorkflowState.bPreparationRetryVisible = false;
		WorkflowState.bSessionReopenVisible = false;
		WorkflowState.Entries.Reset();
		WorkflowState.Issues.Reset();
		WorkflowState.ActiveIssue = FHyperTwistSpeechNativeCaptureRouteWorkflowIssue();
		WorkflowState.ActiveIssueCount = 0;

		if (!SessionState.bSessionOpen)
		{
			FHyperTwistSpeechNativeCaptureRouteWorkflowEntry Entry;
			Entry.EntryId = TEXT("capture-route-session-open-required");
			Entry.SourceKind = TEXT("session-open-required");
			Entry.WorkflowStateId = TEXT("capture-route-session-open-required");
			Entry.CaptureRouteStateId = WorkflowState.CaptureRouteStateId;
			Entry.StatusLine = TEXT("Open the speech session before native capture-route ownership begins.");
			Entry.DetailLine =
				TEXT("The bounded first-party route owner is not active while the speech session is closed. Reopen the session before capture-route assessment continues.");
			Entry.RecommendedActionId = Profile.SessionReopenActionId;
			Entry.bRequiresSessionOpen = true;

			FHyperTwistSpeechNativeCaptureRouteWorkflowIssue Issue;
			Issue.IssueId = TEXT("capture-route-session-open-required");
			Issue.IssueKind = TEXT("session-open-required");
			Issue.StatusLine = Entry.StatusLine;
			Issue.DetailLine = Entry.DetailLine;
			Issue.RecommendedActionId = Entry.RecommendedActionId;

			WorkflowState.Entries.Add(Entry);
			WorkflowState.WorkflowEntryCount = 1;
			WorkflowState.SessionReopenEntryCount = 1;
			WorkflowState.WorkflowStateId = Entry.WorkflowStateId;
			WorkflowState.LatestSourceKind = Entry.SourceKind;
			WorkflowState.StatusLine = Entry.StatusLine;
			WorkflowState.DetailLine = Entry.DetailLine;
			WorkflowState.bRouteOwnershipConfirmed = false;
			WorkflowState.bWorkflowReady = false;
			WorkflowState.bSessionOpenRequired = true;
			WorkflowState.bSessionReopenVisible = Profile.bSupportsSessionReopen;
			AddSpeechNativeCaptureRouteWorkflowIssue(WorkflowState, Issue);
		}
		else if ((PermissionWorkflowState.IsStructurallyValid()
				&& (!PermissionWorkflowState.bPermissionGranted
					|| !PermissionWorkflowState.bPermissionWorkflowReady))
			|| WorkflowState.PermissionStateId != TEXT("permission-granted"))
		{
			FHyperTwistSpeechNativeCaptureRouteWorkflowEntry Entry;
			Entry.EntryId = TEXT("capture-route-permission-dependency");
			Entry.SourceKind = TEXT("permission-workflow-dependency");
			Entry.WorkflowStateId = TEXT("capture-route-awaiting-permission");
			Entry.CaptureRouteStateId = TEXT("route-waiting-for-permission");
			Entry.StatusLine =
				TEXT("Resolve the device-permission workflow before capture-route ownership continues.");
			Entry.DetailLine =
				TEXT("The first-party capture-route owner is waiting on the bounded permission workflow. Clear permission review, request, or recheck posture before route preparation resumes.");
			Entry.RecommendedActionId = Profile.PermissionDependencyActionId;
			Entry.bRequiresPermissionWorkflow = true;

			FHyperTwistSpeechNativeCaptureRouteWorkflowIssue Issue;
			Issue.IssueId = TEXT("capture-route-permission-dependency");
			Issue.IssueKind = TEXT("permission-workflow-dependency");
			Issue.StatusLine = Entry.StatusLine;
			Issue.DetailLine = Entry.DetailLine;
			Issue.RecommendedActionId = Entry.RecommendedActionId;

			WorkflowState.Entries.Add(Entry);
			WorkflowState.WorkflowEntryCount = 1;
			WorkflowState.PermissionDependencyEntryCount = 1;
			WorkflowState.WorkflowStateId = Entry.WorkflowStateId;
			WorkflowState.CaptureRouteStateId = Entry.CaptureRouteStateId;
			WorkflowState.LatestSourceKind = Entry.SourceKind;
			WorkflowState.StatusLine = Entry.StatusLine;
			WorkflowState.DetailLine = Entry.DetailLine;
			WorkflowState.bRouteOwnershipConfirmed = false;
			WorkflowState.bWorkflowReady = false;
			WorkflowState.bPermissionWorkflowBlocked = true;
			AddSpeechNativeCaptureRouteWorkflowIssue(WorkflowState, Issue);
		}
		else if (WorkflowState.CaptureRouteStateId == TEXT("route-awaiting-endpoint")
			|| RouteError == TEXT("service-base-url-missing"))
		{
			FHyperTwistSpeechNativeCaptureRouteWorkflowEntry Entry;
			Entry.EntryId = TEXT("capture-route-preparation-required");
			Entry.SourceKind = TEXT("capture-route-preparation-required");
			Entry.WorkflowStateId = TEXT("capture-route-preparation-required");
			Entry.CaptureRouteStateId = TEXT("route-awaiting-endpoint");
			Entry.StatusLine = TEXT("Native capture route needs preparation before ownership can start.");
			Entry.DetailLine = RouteError.IsEmpty()
				? TEXT("Inspect the selected route, prepare the local sidecar or device path, then reopen the speech session once the bounded route is ready.")
				: FString::Printf(
					TEXT("The capture route reported '%s'. Inspect the selected route, prepare the local sidecar or device path, then reopen the speech session."),
					*RouteError
				);
			Entry.RecommendedActionId = Profile.RouteInspectActionId;
			Entry.bRequiresPreparation = true;

			FHyperTwistSpeechNativeCaptureRouteWorkflowIssue Issue;
			Issue.IssueId = TEXT("capture-route-preparation-required");
			Issue.IssueKind = TEXT("capture-route-preparation-required");
			Issue.StatusLine = Entry.StatusLine;
			Issue.DetailLine = Entry.DetailLine;
			Issue.RecommendedActionId = Entry.RecommendedActionId;

			WorkflowState.Entries.Add(Entry);
			WorkflowState.WorkflowEntryCount = 1;
			WorkflowState.PreparationEntryCount = 1;
			WorkflowState.WorkflowStateId = Entry.WorkflowStateId;
			WorkflowState.CaptureRouteStateId = Entry.CaptureRouteStateId;
			WorkflowState.LatestSourceKind = Entry.SourceKind;
			WorkflowState.StatusLine = Entry.StatusLine;
			WorkflowState.DetailLine = Entry.DetailLine;
			WorkflowState.bRouteOwnershipConfirmed = false;
			WorkflowState.bWorkflowReady = false;
			WorkflowState.bPreparationRequired = true;
			WorkflowState.bRouteInspectVisible = Profile.bSupportsRouteInspect;
			AddSpeechNativeCaptureRouteWorkflowIssue(WorkflowState, Issue);
		}
		else if (WorkflowState.CaptureRouteStateId == TEXT("route-retry-required")
			|| WorkflowState.CaptureRouteStateId == TEXT("route-health-degraded")
			|| (RouteDecision.IsStructurallyValid() && !RouteDecision.bRouteReady)
			|| (IsSpeechRouteError(RouteError) && RouteError != TEXT("no-active-training-run")))
		{
			FHyperTwistSpeechNativeCaptureRouteWorkflowEntry Entry;
			Entry.EntryId = TEXT("capture-route-retry-required");
			Entry.SourceKind = TEXT("capture-route-retry-required");
			Entry.WorkflowStateId = TEXT("capture-route-retry-required");
			Entry.CaptureRouteStateId = TEXT("route-retry-required");
			Entry.StatusLine = TEXT("Native capture route must be rechecked before ownership resumes.");
			Entry.DetailLine = RouteError.IsEmpty()
				? TEXT("The bounded route owner cannot confirm capture readiness yet. Retry the capture route once the sidecar or device path reports healthy again.")
				: FString::Printf(
					TEXT("The capture route reported '%s'. Retry the route once the sidecar or device path reports healthy again."),
					*RouteError
				);
			Entry.RecommendedActionId = Profile.PreparationRetryActionId;
			Entry.bRequiresRouteRetry = true;

			FHyperTwistSpeechNativeCaptureRouteWorkflowIssue Issue;
			Issue.IssueId = TEXT("capture-route-retry-required");
			Issue.IssueKind = TEXT("capture-route-retry-required");
			Issue.StatusLine = Entry.StatusLine;
			Issue.DetailLine = Entry.DetailLine;
			Issue.RecommendedActionId = Entry.RecommendedActionId;

			WorkflowState.Entries.Add(Entry);
			WorkflowState.WorkflowEntryCount = 1;
			WorkflowState.RouteRetryEntryCount = 1;
			WorkflowState.WorkflowStateId = Entry.WorkflowStateId;
			WorkflowState.CaptureRouteStateId = Entry.CaptureRouteStateId;
			WorkflowState.LatestSourceKind = Entry.SourceKind;
			WorkflowState.StatusLine = Entry.StatusLine;
			WorkflowState.DetailLine = Entry.DetailLine;
			WorkflowState.bRouteOwnershipConfirmed = false;
			WorkflowState.bWorkflowReady = false;
			WorkflowState.bPreparationRetryVisible = Profile.bSupportsPreparationRetry;
			AddSpeechNativeCaptureRouteWorkflowIssue(WorkflowState, Issue);
		}

		WorkflowState.ActiveIssueCount = WorkflowState.Issues.Num();
	}

	void SynchronizeSpeechNativeCaptureRouteWorkflowState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		if (EffectiveConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty())
		{
			EffectiveConfig.NativeCaptureRouteWorkflowProfileId =
				TEXT("speech-native-capture-route-workflow-v1");
		}
		const FHyperTwistSpeechNativeCaptureRouteWorkflowProfile Profile =
			EffectiveConfig.NativeCaptureRouteWorkflowProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.NativeCaptureRouteWorkflowProfileDefinition
				: BuildDefaultSpeechNativeCaptureRouteWorkflowProfile(
					!EffectiveConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty()
						? EffectiveConfig.NativeCaptureRouteWorkflowProfileId
						: TEXT("speech-native-capture-route-workflow-v1")
				);

		if (!SessionState.NativeCaptureRouteWorkflowState.IsStructurallyValid())
		{
			SessionState.NativeCaptureRouteWorkflowState =
				BuildSpeechNativeCaptureRouteWorkflowState(EffectiveConfig, &SessionState);
		}

		FHyperTwistSpeechNativeCaptureRouteWorkflowState& WorkflowState =
			SessionState.NativeCaptureRouteWorkflowState;
		WorkflowState.NativeCaptureRouteWorkflowProfileId =
			Profile.NativeCaptureRouteWorkflowProfileId;
		WorkflowState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			WorkflowState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechNativeCaptureRouteWorkflowPosture(Profile, SessionState, WorkflowState);
	}

	void ApplySpeechNativeCaptureRouteShellPosture(
		const FHyperTwistSpeechNativeCaptureRouteShellProfile& Profile,
		const FHyperTwistSpeechNativeCaptureRouteWorkflowState& WorkflowState,
		FHyperTwistSpeechNativeCaptureRouteShellState& ShellState
	)
	{
		ShellState.NativeCaptureRouteWorkflowProfileId =
			WorkflowState.NativeCaptureRouteWorkflowProfileId;
		ShellState.ActiveProviderProfileId = WorkflowState.ActiveProviderProfileId;
		ShellState.ActiveServiceLaneId = WorkflowState.ActiveServiceLaneId;
		ShellState.WorkflowStateId = WorkflowState.WorkflowStateId;
		ShellState.CaptureRouteStateId = WorkflowState.CaptureRouteStateId;
		ShellState.PermissionStateId = WorkflowState.PermissionStateId;
		ShellState.LatestSourceKind = WorkflowState.LatestSourceKind;
		ShellState.StatusLine = WorkflowState.StatusLine;
		ShellState.DetailLine = WorkflowState.DetailLine;
		ShellState.LastRouteError = WorkflowState.LastRouteError;
		ShellState.bShellVisible = true;
		ShellState.bOwnershipSummaryVisible = Profile.bSupportsOwnershipSummaryCard;
		ShellState.bPreparationCardVisible =
			Profile.bSupportsPreparationCard
			&& (WorkflowState.bPreparationRequired
				|| WorkflowState.bPreparationRetryVisible
				|| WorkflowState.RouteRetryEntryCount > 0);
		ShellState.bSessionReopenCardVisible =
			Profile.bSupportsSessionReopenCard
			&& (WorkflowState.bSessionOpenRequired
				|| WorkflowState.bSessionReopenVisible
				|| WorkflowState.SessionReopenEntryCount > 0);
		ShellState.bPermissionDependencyBannerVisible =
			Profile.bSupportsPermissionDependencyBanner
			&& WorkflowState.bPermissionWorkflowBlocked;
		ShellState.bRouteOwnershipConfirmed = WorkflowState.bRouteOwnershipConfirmed;
		ShellState.bWorkflowReady = WorkflowState.bWorkflowReady;
		ShellState.bPreparationRequired = WorkflowState.bPreparationRequired;
		ShellState.bSessionOpenRequired = WorkflowState.bSessionOpenRequired;
		ShellState.bPermissionWorkflowBlocked = WorkflowState.bPermissionWorkflowBlocked;
		ShellState.bRouteInspectVisible = WorkflowState.bRouteInspectVisible;
		ShellState.bPreparationRetryVisible = WorkflowState.bPreparationRetryVisible;
		ShellState.bSessionReopenVisible = WorkflowState.bSessionReopenVisible;
		ShellState.ActiveIssue = WorkflowState.ActiveIssue;
		ShellState.Entries = WorkflowState.Entries;
		ShellState.Issues = WorkflowState.Issues;
		ShellState.ActiveIssueCount = WorkflowState.ActiveIssueCount;
	}

	void SynchronizeSpeechNativeCaptureRouteShellState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		if (EffectiveConfig.NativeCaptureRouteShellProfileId.IsEmpty())
		{
			EffectiveConfig.NativeCaptureRouteShellProfileId =
				TEXT("speech-native-capture-route-shell-v1");
		}
		const FHyperTwistSpeechNativeCaptureRouteShellProfile Profile =
			EffectiveConfig.NativeCaptureRouteShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.NativeCaptureRouteShellProfileDefinition
				: BuildDefaultSpeechNativeCaptureRouteShellProfile(
					!EffectiveConfig.NativeCaptureRouteShellProfileId.IsEmpty()
						? EffectiveConfig.NativeCaptureRouteShellProfileId
						: TEXT("speech-native-capture-route-shell-v1")
				);

		if (!SessionState.NativeCaptureRouteWorkflowState.IsStructurallyValid())
		{
			SessionState.NativeCaptureRouteWorkflowState =
				BuildSpeechNativeCaptureRouteWorkflowState(EffectiveConfig, &SessionState);
		}
		if (!SessionState.NativeCaptureRouteShellState.IsStructurallyValid())
		{
			SessionState.NativeCaptureRouteShellState =
				BuildSpeechNativeCaptureRouteShellState(EffectiveConfig, &SessionState);
		}

		FHyperTwistSpeechNativeCaptureRouteShellState& ShellState =
			SessionState.NativeCaptureRouteShellState;
		ShellState.NativeCaptureRouteShellProfileId =
			Profile.NativeCaptureRouteShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechNativeCaptureRouteShellPosture(
			Profile,
			SessionState.NativeCaptureRouteWorkflowState,
			ShellState
		);

		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.PreparationRetryActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.SessionReopenActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.PermissionDependencyActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	TArray<FHyperTwistSpeechExternalDictationOutputRouteOption>
	BuildDefaultSpeechExternalDictationOutputRouteOptions()
	{
		TArray<FHyperTwistSpeechExternalDictationOutputRouteOption> OutputRoutes;

		FHyperTwistSpeechExternalDictationOutputRouteOption ClipboardRoute;
		ClipboardRoute.OutputRouteId = TEXT("clipboard-paste");
		ClipboardRoute.DisplayLabel = TEXT("Paste to active app");
		ClipboardRoute.DeliveryModeId = TEXT("clipboard-paste");
		ClipboardRoute.DispatchTargetId = TEXT("active-clipboard-target");
		ClipboardRoute.InputGestureHint = TEXT("Ctrl+Shift+V");
		ClipboardRoute.bRouteSelectable = true;
		ClipboardRoute.bDefaultSelected = true;
		ClipboardRoute.bRequiresFocusedDesktopTarget = true;
		ClipboardRoute.bSupportsTranscriptPostProcess = true;
		OutputRoutes.Add(ClipboardRoute);

		FHyperTwistSpeechExternalDictationOutputRouteOption TypingRoute;
		TypingRoute.OutputRouteId = TEXT("direct-typing");
		TypingRoute.DisplayLabel = TEXT("Type into focused app");
		TypingRoute.DeliveryModeId = TEXT("direct-typing");
		TypingRoute.DispatchTargetId = TEXT("focused-desktop-target");
		TypingRoute.InputGestureHint = TEXT("Ctrl+Shift+T");
		TypingRoute.bRouteSelectable = true;
		TypingRoute.bDefaultSelected = false;
		TypingRoute.bRequiresFocusedDesktopTarget = true;
		TypingRoute.bSupportsTranscriptPostProcess = true;
		OutputRoutes.Add(TypingRoute);

		FHyperTwistSpeechExternalDictationOutputRouteOption ScriptRoute;
		ScriptRoute.OutputRouteId = TEXT("script-dispatch");
		ScriptRoute.DisplayLabel = TEXT("Dispatch script hook");
		ScriptRoute.DeliveryModeId = TEXT("script-dispatch");
		ScriptRoute.DispatchTargetId = TEXT("user-script-hook");
		ScriptRoute.InputGestureHint = TEXT("Ctrl+Shift+R");
		ScriptRoute.bRouteSelectable = true;
		ScriptRoute.bDefaultSelected = false;
		ScriptRoute.bRequiresFocusedDesktopTarget = false;
		ScriptRoute.bSupportsTranscriptPostProcess = true;
		OutputRoutes.Add(ScriptRoute);

		return OutputRoutes;
	}

	FString NormalizeSpeechExternalDictationPostProcessedText(const FString& TranscriptText)
	{
		FString Normalized = TranscriptText;
		Normalized.ReplaceInline(TEXT("\r"), TEXT(" "));
		Normalized.ReplaceInline(TEXT("\n"), TEXT(" "));
		TArray<FString> Tokens;
		Normalized.ParseIntoArrayWS(Tokens);
		return Tokens.Num() > 0 ? FString::Join(Tokens, TEXT(" ")) : FString();
	}

	FString BuildSpeechExternalDictationSourceKind(
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		if (!SessionState.LastError.IsEmpty() && !SessionState.ServiceHealth.bReady)
		{
			return TEXT("provider-fallback-health");
		}
		if (SessionState.MicrophoneShellState.bTranscriptionInFlight)
		{
			return TEXT("transcription-in-flight");
		}
		if (SessionState.bHasTranscriptResult
			&& SessionState.LastTranscriptResult.bIsFinal
			&& SessionState.LastTranscriptResult.IsStructurallyValid())
		{
			return TEXT("final-transcript");
		}
		if (SessionState.bSessionOpen)
		{
			return TEXT("session-open-ready");
		}

		return TEXT("shell-cleared");
	}

	FString BuildSpeechExternalDictationSignature(
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		const FString& PostProcessedText
	)
	{
		const FHyperTwistSpeechTranscriptResult& Result = SessionState.LastTranscriptResult;
		return FString::Printf(
			TEXT("%s|%s|%s|%s|%d|%s"),
			*Result.SessionId,
			*Result.UtteranceId,
			*Result.TranscriptText,
			*PostProcessedText,
			Result.bIsFinal ? 1 : 0,
			*SessionState.LastError
		);
	}

	FHyperTwistSpeechExternalDictationHistoryEntry BuildSpeechExternalDictationHistoryEntry(
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		const FHyperTwistSpeechExternalDictationShellState& ShellState,
		const FString& PostProcessedText,
		const int32 EntryOrdinal
	)
	{
		FHyperTwistSpeechExternalDictationHistoryEntry Entry;
		const FString EffectiveSessionId =
			!SessionState.ActiveSessionId.IsEmpty()
				? SessionState.ActiveSessionId
				: (!SessionState.SessionConfig.SessionId.IsEmpty()
					? SessionState.SessionConfig.SessionId
					: TEXT("speech-session-default"));
		const FHyperTwistSpeechTranscriptResult& Result = SessionState.LastTranscriptResult;

		Entry.HistoryEntryId = FString::Printf(
			TEXT("speech-external-dictation-history/%s/%02d"),
			*EffectiveSessionId,
			FMath::Max(EntryOrdinal, 1)
		);
		Entry.SourceKind = BuildSpeechExternalDictationSourceKind(SessionState);
		Entry.SessionId = EffectiveSessionId;
		Entry.UtteranceId = Result.UtteranceId;
		Entry.ProviderProfileId = SessionState.ServiceHealth.ProviderProfileDefinition.IsStructurallyValid()
			? SessionState.ServiceHealth.ProviderProfileDefinition.ProviderProfileId
			: (SessionState.SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
				? SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId
				: TEXT("speech-provider/local-http-sidecar-profile-v1"));
		Entry.ServiceLaneId = !SessionState.ServiceHealth.ProviderRouteDecision.SelectedServiceLaneId.IsEmpty()
			? SessionState.ServiceHealth.ProviderRouteDecision.SelectedServiceLaneId
			: (!SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
				? SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId
				: TEXT("speech/python-service"));
		Entry.CapturedAtUtc = !SessionState.LastUpdatedAtUtc.IsEmpty()
			? SessionState.LastUpdatedAtUtc
			: FDateTime::UtcNow().ToIso8601();
		Entry.TranscriptText = Result.TranscriptText;
		Entry.PostProcessedText = PostProcessedText;
		Entry.OutputRouteId = !ShellState.SelectedOutputRouteId.IsEmpty()
			? ShellState.SelectedOutputRouteId
			: TEXT("clipboard-paste");
		Entry.bIsFinal = Result.bIsFinal;
		Entry.bPostProcessed = !PostProcessedText.IsEmpty() && PostProcessedText != Result.TranscriptText;
		Entry.bSaved = false;
		Entry.bClipboardReady = true;
		Entry.bTypingReady = true;
		Entry.bScriptDispatchReady = true;
		return Entry;
	}

	FString BuildSpeechExternalDictationModelCatalogLabel(
		const FHyperTwistSpeechModelPayloadDescriptor& Payload
	)
	{
		if (!Payload.ModelFamily.IsEmpty() && !Payload.VariantId.IsEmpty())
		{
			return FString::Printf(TEXT("%s %s"), *Payload.ModelFamily, *Payload.VariantId);
		}
		if (!Payload.ArtifactName.IsEmpty())
		{
			return Payload.ArtifactName;
		}
		return Payload.PayloadId;
	}

	TArray<FHyperTwistSpeechExternalDictationModelCatalogEntry>
	BuildSpeechExternalDictationModelCatalogEntries(
		const FHyperTwistSpeechPayloadCustodyProfile& PayloadCustodyProfile,
		const TArray<FHyperTwistSpeechModelPayloadDescriptor>& Payloads
	)
	{
		TArray<FHyperTwistSpeechExternalDictationModelCatalogEntry> Entries;
		Entries.Reserve(Payloads.Num());
		for (const FHyperTwistSpeechModelPayloadDescriptor& Payload : Payloads)
		{
			if (!Payload.IsStructurallyValid())
			{
				continue;
			}

			FHyperTwistSpeechExternalDictationModelCatalogEntry Entry;
			Entry.PayloadId = Payload.PayloadId;
			Entry.DisplayLabel = BuildSpeechExternalDictationModelCatalogLabel(Payload);
			Entry.PayloadKind = Payload.PayloadKind;
			Entry.SelectionPolicyId = Payload.bOptionalForSession
				? TEXT("optional-adjunct-payload")
				: TEXT("primary-transcription-model");
			Entry.AcquisitionMode = Payload.AcquisitionMode;
			Entry.IntegrityCheckKind = Payload.IntegrityCheckKind;
			Entry.IntegrityCheckValue = Payload.IntegrityCheckValue;
			Entry.RelativePathHint = Payload.RelativePathHint;
			Entry.StoragePostureId = Payload.bUserSuppliedOnly
				? TEXT("user-managed-local-cache")
				: TEXT("sidecar-managed-local-cache");
			Entry.UnloadPolicyId = Payload.bOptionalForSession
				? TEXT("optional-payload-unload-review")
				: TEXT("primary-model-unload-review");
			Entry.ApproximateSizeMiB = Payload.ApproximateSizeMiB;
			Entry.bOptionalForSession = Payload.bOptionalForSession;
			Entry.bSelectedPrimaryPayload = !Payload.bOptionalForSession;
			Entry.bDownloadDeferredInCurrentPacket =
				!PayloadCustodyProfile.bAllowsRuntimeDownloadInCurrentPacket;
			Entry.bIntegrityReviewRequired =
				PayloadCustodyProfile.bRequiresIntegrityVerification
				&& !Payload.IntegrityCheckKind.IsEmpty();
			Entry.bUnloadActionDeferredInCurrentPacket = true;
			Entries.Add(Entry);
		}
		return Entries;
	}

	void ApplySpeechExternalDictationModelCatalogPosture(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistSpeechServiceHealth& ServiceHealth,
		FHyperTwistSpeechExternalDictationShellState& ShellState
	)
	{
		const FHyperTwistSpeechPayloadCustodyProfile EffectivePayloadCustodyProfile =
			ServiceHealth.PayloadCustodyProfileDefinition.IsStructurallyValid()
				? ServiceHealth.PayloadCustodyProfileDefinition
				: (SessionConfig.PayloadCustodyProfileDefinition.IsStructurallyValid()
					? SessionConfig.PayloadCustodyProfileDefinition
					: BuildDefaultSpeechPayloadCustodyProfile(
						!SessionConfig.PayloadCustodyProfileId.IsEmpty()
							? SessionConfig.PayloadCustodyProfileId
							: TEXT("downloadable-model-payload-custody-v1")
					));
		const TArray<FHyperTwistSpeechModelPayloadDescriptor> EffectivePayloads =
			ServiceHealth.SupportedModelPayloads.Num() > 0
				? ServiceHealth.SupportedModelPayloads
				: (SessionConfig.RequiredModelPayloads.Num() > 0
					? SessionConfig.RequiredModelPayloads
					: BuildDefaultSpeechModelPayloads());

		ShellState.PayloadCustodyProfileId =
			EffectivePayloadCustodyProfile.PayloadCustodyProfileId;
		ShellState.ModelCatalogEntries =
			BuildSpeechExternalDictationModelCatalogEntries(
				EffectivePayloadCustodyProfile,
				EffectivePayloads
			);
		ShellState.ModelCatalogEntryCount = ShellState.ModelCatalogEntries.Num();
		ShellState.OptionalModelCatalogEntryCount = 0;
		ShellState.DownloadDeferredModelEntryCount = 0;
		ShellState.IntegrityReviewRequiredEntryCount = 0;
		ShellState.SelectedPrimaryPayloadId.Reset();
		for (const FHyperTwistSpeechExternalDictationModelCatalogEntry& Entry :
			ShellState.ModelCatalogEntries)
		{
			if (Entry.bOptionalForSession)
			{
				++ShellState.OptionalModelCatalogEntryCount;
			}
			if (Entry.bDownloadDeferredInCurrentPacket)
			{
				++ShellState.DownloadDeferredModelEntryCount;
			}
			if (Entry.bIntegrityReviewRequired)
			{
				++ShellState.IntegrityReviewRequiredEntryCount;
			}
			if (ShellState.SelectedPrimaryPayloadId.IsEmpty() && Entry.bSelectedPrimaryPayload)
			{
				ShellState.SelectedPrimaryPayloadId = Entry.PayloadId;
			}
		}
		if (ShellState.SelectedPrimaryPayloadId.IsEmpty()
			&& ShellState.ModelCatalogEntries.Num() > 0)
		{
			ShellState.SelectedPrimaryPayloadId = ShellState.ModelCatalogEntries[0].PayloadId;
		}

		ShellState.bCatalogReady = ShellState.ModelCatalogEntries.Num() > 0;
		ShellState.bRuntimeDownloadDeferred =
			!EffectivePayloadCustodyProfile.bAllowsRuntimeDownloadInCurrentPacket;
		ShellState.bBundledPayloadRedistributionDeferred =
			!EffectivePayloadCustodyProfile.bAllowsBundledPayloadRedistribution;
		ShellState.bSupportsUserManagedPayloads =
			EffectivePayloadCustodyProfile.bSupportsUserManagedPayloads;
		ShellState.bSupportsSidecarManagedPayloads =
			EffectivePayloadCustodyProfile.bSupportsSidecarManagedPayloads;
		ShellState.bIntegrityVerificationRequired =
			EffectivePayloadCustodyProfile.bRequiresIntegrityVerification;
		ShellState.bUnloadActionsDeferredToSidecar = true;
	}

	void AddSpeechExternalDictationShellIssue(
		FHyperTwistSpeechExternalDictationShellState& ShellState,
		const FHyperTwistSpeechExternalDictationShellIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void AppendSpeechExternalDictationHistoryEntry(
		const FHyperTwistSpeechExternalDictationShellProfile& Profile,
		const FString& Signature,
		const FHyperTwistSpeechExternalDictationHistoryEntry& Entry,
		FHyperTwistSpeechExternalDictationShellState& ShellState
	)
	{
		if (!Entry.IsStructurallyValid() || ShellState.LastRecordedSignature == Signature)
		{
			return;
		}

		ShellState.HistoryEntries.Add(Entry);
		while (ShellState.HistoryEntries.Num() > Profile.RetainedHistoryEntryLimit)
		{
			ShellState.HistoryEntries.RemoveAt(0);
		}
		ShellState.LastRecordedSignature = Signature;
	}

	void ApplySpeechExternalDictationShellPosture(
		const FHyperTwistSpeechExternalDictationShellProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechExternalDictationShellState& ShellState
	)
	{
		ShellState.ActiveProviderProfileId =
			SessionState.ServiceHealth.ProviderProfileDefinition.IsStructurallyValid()
				? SessionState.ServiceHealth.ProviderProfileDefinition.ProviderProfileId
				: (SessionState.SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
					? SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId
					: TEXT("speech-provider/local-http-sidecar-profile-v1"));
		ShellState.ActiveServiceLaneId =
			!SessionState.ServiceHealth.ProviderRouteDecision.SelectedServiceLaneId.IsEmpty()
				? SessionState.ServiceHealth.ProviderRouteDecision.SelectedServiceLaneId
				: (!SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
					? SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId
					: TEXT("speech/python-service"));
		ShellState.TranscriptHistorySurfaceModeId = Profile.TranscriptHistorySurfaceMode;
		ShellState.OutputRoutingSurfaceModeId = Profile.OutputRoutingSurfaceMode;
		ShellState.PostProcessOverlaySurfaceModeId = Profile.PostProcessOverlaySurfaceMode;
		ShellState.GlobalHotkeySurfaceModeId = Profile.GlobalHotkeySurfaceMode;
		ShellState.InputDeviceSurfaceModeId = Profile.InputDeviceSurfaceMode;
		ShellState.OutputDeviceSurfaceModeId = Profile.OutputDeviceSurfaceMode;
		ShellState.MuteSurfaceModeId = Profile.MuteSurfaceMode;
		ShellState.MicrophoneModeSurfaceModeId = Profile.MicrophoneModeSurfaceMode;
		ShellState.LocalModelCatalogSurfaceModeId = Profile.LocalModelCatalogSurfaceMode;
		ShellState.ModelIntegritySurfaceModeId = Profile.ModelIntegritySurfaceMode;
		ShellState.ModelUnloadSurfaceModeId = Profile.ModelUnloadSurfaceMode;
		ShellState.PrimaryHotkeyBindingLabel = Profile.PrimaryHotkeyBindingLabel;
		ShellState.PostProcessHotkeyBindingLabel = Profile.PostProcessHotkeyBindingLabel;
		ShellState.SelectedInputDeviceId = TEXT("system-default-input");
		ShellState.SelectedInputDeviceLabel = TEXT("System default microphone");
		ShellState.SelectedOutputDeviceId = TEXT("system-default-output");
		ShellState.SelectedOutputDeviceLabel = TEXT("System default output device");
		ShellState.MicrophoneModeId = TEXT("on-demand");
		ShellState.bShellVisible = true;
		ShellState.bTranscriptHistoryVisible = Profile.bSupportsTranscriptHistoryTimeline;
		ShellState.bOutputRoutingVisible =
			Profile.bSupportsClipboardRouting
			|| Profile.bSupportsTypingRouting
			|| Profile.bSupportsScriptDispatchRouting;
		ShellState.bPostProcessOverlayVisible = Profile.bSupportsTranscriptPostProcessOverlay;
		ShellState.bGlobalHotkeyVisible = Profile.bSupportsGlobalHotkeyLifecycle;
		ShellState.bInputDeviceSelectionVisible = Profile.bSupportsInputDeviceSelection;
		ShellState.bOutputDeviceSelectionVisible = Profile.bSupportsOutputDeviceSelection;
		ShellState.bMuteWhileRecordingVisible = Profile.bSupportsMuteWhileRecordingToggle;
		ShellState.bMicrophoneModeVisible = Profile.bSupportsAlwaysOnMicrophoneMode;
		ShellState.bLocalModelCatalogVisible = Profile.bSupportsLocalModelCatalogReview;
		ShellState.bModelIntegrityVisible = Profile.bSupportsModelIntegrityReview;
		ShellState.bModelUnloadPolicyVisible = Profile.bSupportsModelUnloadPolicyReview;
		ShellState.bClamshellInputFallbackVisible = Profile.bSupportsClamshellInputFallback;
		ShellState.bLazyCloseLifecycleVisible = Profile.bSupportsLazyCloseLifecycle;
		ShellState.bPushToTalkReady = SessionState.bSessionOpen && SessionState.ServiceHealth.bReady;
		ShellState.bCaptureInFlight = SessionState.MicrophoneShellState.bTranscriptionInFlight;
		ShellState.bCancelVisible = ShellState.bCaptureInFlight;
		ShellState.bOutputRoutingReady =
			SessionState.bHasTranscriptResult
			&& SessionState.LastTranscriptResult.bIsFinal
			&& SessionState.LastTranscriptResult.IsStructurallyValid();
		ShellState.bClipboardRouteAvailable = Profile.bSupportsClipboardRouting;
		ShellState.bTypingRouteAvailable = Profile.bSupportsTypingRouting;
		ShellState.bScriptRouteAvailable = Profile.bSupportsScriptDispatchRouting;
		ShellState.bPostProcessOverlayEnabled = Profile.bSupportsTranscriptPostProcessOverlay;
		ShellState.bPushToTalkMode = true;
		ShellState.bMuteWhileRecordingEnabled = false;
		ShellState.LatestSourceKind = BuildSpeechExternalDictationSourceKind(SessionState);
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechExternalDictationShellIssue();

		if (ShellState.OutputRouteOptions.Num() <= 0)
		{
			ShellState.OutputRouteOptions = BuildDefaultSpeechExternalDictationOutputRouteOptions();
		}
		if (ShellState.SelectedOutputRouteId.IsEmpty())
		{
			for (const FHyperTwistSpeechExternalDictationOutputRouteOption& OutputRoute :
				ShellState.OutputRouteOptions)
			{
				if (OutputRoute.bDefaultSelected)
				{
					ShellState.SelectedOutputRouteId = OutputRoute.OutputRouteId;
					break;
				}
			}
			if (ShellState.SelectedOutputRouteId.IsEmpty() && ShellState.OutputRouteOptions.Num() > 0)
			{
				ShellState.SelectedOutputRouteId = ShellState.OutputRouteOptions[0].OutputRouteId;
			}
		}

		if (ShellState.InputDeviceOptions.Num() <= 0)
		{
			ShellState.InputDeviceOptions = BuildDefaultSpeechExternalDictationInputDeviceOptions();
		}
		if (ShellState.OutputDeviceOptions.Num() <= 0)
		{
			ShellState.OutputDeviceOptions = BuildDefaultSpeechExternalDictationOutputDeviceOptions();
		}

		auto ApplySelectedDeviceDefaults = [](
			const TArray<FHyperTwistSpeechExternalDictationDeviceOption>& DeviceOptions,
			const TCHAR* FallbackDeviceId,
			const TCHAR* FallbackDeviceLabel,
			FString& SelectedDeviceId,
			FString& SelectedDeviceLabel
		)
		{
			const FHyperTwistSpeechExternalDictationDeviceOption* SelectedDevice =
				DeviceOptions.FindByPredicate(
					[](const FHyperTwistSpeechExternalDictationDeviceOption& DeviceOption)
					{
						return DeviceOption.bSelectedRoute;
					}
				);
			if (SelectedDevice == nullptr)
			{
				SelectedDevice = DeviceOptions.FindByPredicate(
					[](const FHyperTwistSpeechExternalDictationDeviceOption& DeviceOption)
					{
						return DeviceOption.bDefaultRoute;
					}
				);
			}
			if (SelectedDevice == nullptr && DeviceOptions.Num() > 0)
			{
				SelectedDevice = &DeviceOptions[0];
			}

			SelectedDeviceId =
				SelectedDevice != nullptr && !SelectedDevice->DeviceId.IsEmpty()
					? SelectedDevice->DeviceId
					: FallbackDeviceId;
			SelectedDeviceLabel =
				SelectedDevice != nullptr && !SelectedDevice->DisplayLabel.IsEmpty()
					? SelectedDevice->DisplayLabel
					: FallbackDeviceLabel;
		};

		ApplySelectedDeviceDefaults(
			ShellState.InputDeviceOptions,
			TEXT("system-default-input"),
			TEXT("System default microphone"),
			ShellState.SelectedInputDeviceId,
			ShellState.SelectedInputDeviceLabel
		);
		ApplySelectedDeviceDefaults(
			ShellState.OutputDeviceOptions,
			TEXT("system-default-output"),
			TEXT("System default output device"),
			ShellState.SelectedOutputDeviceId,
			ShellState.SelectedOutputDeviceLabel
		);
		ApplySpeechExternalDictationModelCatalogPosture(
			SessionState.SessionConfig,
			SessionState.ServiceHealth,
			ShellState
		);

		bool bSelectedRouteFound = false;
		for (const FHyperTwistSpeechExternalDictationOutputRouteOption& OutputRoute :
			ShellState.OutputRouteOptions)
		{
			if (OutputRoute.OutputRouteId == ShellState.SelectedOutputRouteId)
			{
				bSelectedRouteFound = true;
				break;
			}
		}
		if (!bSelectedRouteFound && ShellState.OutputRouteOptions.Num() > 0)
		{
			ShellState.SelectedOutputRouteId = ShellState.OutputRouteOptions[0].OutputRouteId;
		}

		if (SessionState.bHasTranscriptResult
			&& SessionState.LastTranscriptResult.bIsFinal
			&& SessionState.LastTranscriptResult.IsStructurallyValid())
		{
			const FString PostProcessedText = NormalizeSpeechExternalDictationPostProcessedText(
				SessionState.LastTranscriptResult.TranscriptText
			);
			AppendSpeechExternalDictationHistoryEntry(
				Profile,
				BuildSpeechExternalDictationSignature(SessionState, PostProcessedText),
				BuildSpeechExternalDictationHistoryEntry(
					SessionState,
					ShellState,
					PostProcessedText,
					ShellState.HistoryEntries.Num() + 1
				),
				ShellState
			);
		}

		ShellState.HistoryEntryCount = ShellState.HistoryEntries.Num();
		ShellState.PostProcessedEntryCount = 0;
		ShellState.SavedEntryCount = 0;
		for (const FHyperTwistSpeechExternalDictationHistoryEntry& Entry : ShellState.HistoryEntries)
		{
			if (Entry.bPostProcessed)
			{
				++ShellState.PostProcessedEntryCount;
			}
			if (Entry.bSaved)
			{
				++ShellState.SavedEntryCount;
			}
		}

		if (ShellState.HistoryEntries.Num() > 0)
		{
			const FHyperTwistSpeechExternalDictationHistoryEntry& LatestEntry =
				ShellState.HistoryEntries.Last();
			ShellState.LatestHistoryEntryId = LatestEntry.HistoryEntryId;
			ShellState.LatestTranscriptText = LatestEntry.TranscriptText;
			ShellState.LatestPostProcessedText = !LatestEntry.PostProcessedText.IsEmpty()
				? LatestEntry.PostProcessedText
				: LatestEntry.TranscriptText;
			ShellState.bLatestEntryReadyForDispatch =
				LatestEntry.bClipboardReady
				|| LatestEntry.bTypingReady
				|| LatestEntry.bScriptDispatchReady;
		}
		else
		{
			ShellState.LatestHistoryEntryId.Reset();
			ShellState.LatestTranscriptText.Reset();
			ShellState.LatestPostProcessedText.Reset();
			ShellState.bLatestEntryReadyForDispatch = false;
		}

		if (!SessionState.bSessionOpen)
		{
			FHyperTwistSpeechExternalDictationShellIssue Issue;
			Issue.IssueId = TEXT("external-dictation-session-closed");
			Issue.IssueKind = TEXT("session-closed");
			Issue.StatusLine = TEXT("External dictation shell session closed.");
			Issue.DetailLine =
				TEXT("Reopen the bounded speech session before using push-to-talk dictation or output routing.");
			Issue.RecommendedActionId = Profile.ReopenSpeechSessionActionId;
			AddSpeechExternalDictationShellIssue(ShellState, Issue);
		}
		else if (!SessionState.LastError.IsEmpty() && !SessionState.ServiceHealth.bReady)
		{
			FHyperTwistSpeechExternalDictationShellIssue Issue;
			Issue.IssueId = TEXT("external-dictation-route-degraded");
			Issue.IssueKind = TEXT("route-degraded");
			Issue.StatusLine = TEXT("External dictation shell route degraded.");
			Issue.DetailLine = FString::Printf(
				TEXT("The bounded dictation shell captured '%s'. Inspect the provider route before treating output routing as current."),
				*SessionState.LastError
			);
			Issue.RecommendedActionId = Profile.RouteInspectActionId;
			AddSpeechExternalDictationShellIssue(ShellState, Issue);
		}

		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.StatusLine = ShellState.ActiveIssue.StatusLine;
			ShellState.DetailLine = ShellState.ActiveIssue.DetailLine;
		}
		else if (ShellState.HistoryEntries.Num() > 0)
		{
			ShellState.StatusLine =
				TEXT("External dictation shell retained the latest transcript for bounded routing.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d retained transcripts are available for clipboard, typing, or script-oriented output routing."),
				ShellState.HistoryEntryCount
			);
		}
		else if (ShellState.bCaptureInFlight)
		{
			ShellState.StatusLine = TEXT("External dictation shell transcription in flight.");
			ShellState.DetailLine =
				TEXT("The bounded dictation shell is waiting for the current transcript before output routing unlocks.");
		}
		else
		{
			ShellState.StatusLine = TEXT("External dictation shell ready for bounded transcript routing.");
			ShellState.DetailLine =
				TEXT("Push-to-talk dictation, transcript history, local model catalog review, and output routing stay above the landed speech stack without displacing provider/session ownership.");
		}

		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechExternalDictationShellState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		ApplySpeechExternalDictationDefaults(EffectiveConfig);
		if (!SessionState.ExternalDictationShellState.IsStructurallyValid())
		{
			SessionState.ExternalDictationShellState =
				BuildSpeechExternalDictationShellState(EffectiveConfig, &SessionState);
		}

		const FHyperTwistSpeechExternalDictationShellProfile Profile =
			EffectiveConfig.ExternalDictationShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.ExternalDictationShellProfileDefinition
				: BuildDefaultSpeechExternalDictationShellProfile(
					!EffectiveConfig.ExternalDictationShellProfileId.IsEmpty()
						? EffectiveConfig.ExternalDictationShellProfileId
						: TEXT("speech-external-dictation-shell-v1")
				);

		FHyperTwistSpeechExternalDictationShellState& ShellState =
			SessionState.ExternalDictationShellState;
		ShellState.ExternalDictationShellProfileId = Profile.ExternalDictationShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechExternalDictationShellPosture(Profile, SessionState, ShellState);

		ShellState.AvailableActionIds.AddUnique(Profile.StartCaptureActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.CancelCaptureActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.CycleOutputRouteActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.CopyTranscriptActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.PasteTranscriptActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ScriptDispatchActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.TogglePostProcessOverlayActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ReopenSpeechSessionActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.InspectLocalModelCatalogActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ReviewLocalModelIntegrityActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ReviewLocalModelUnloadPolicyActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	void AddSpeechUsageCostDashboardIssue(
		FHyperTwistSpeechUsageCostDashboardShellState& ShellState,
		const FHyperTwistSpeechUsageCostDashboardIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechUsageCostDashboardPosture(
		const FHyperTwistSpeechUsageCostDashboardShellProfile& Profile,
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistSpeechServiceHealth& ServiceHealth,
		const FString& LastError,
		FHyperTwistSpeechUsageCostDashboardShellState& ShellState
	)
	{
		const FHyperTwistSpeechProviderProfile EffectiveProfile =
			ServiceHealth.ProviderProfileDefinition.IsStructurallyValid()
				? ServiceHealth.ProviderProfileDefinition
				: (SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
					? SessionConfig.ProviderProfileDefinition
					: BuildDefaultHttpSpeechProviderProfile(
						TEXT("Local HTTP Speech Sidecar"),
						TEXT("http://127.0.0.1:8766")
					));
		const FHyperTwistSpeechProviderRouteDecision EffectiveRouteDecision =
			ServiceHealth.ProviderRouteDecision.IsStructurallyValid()
				? ServiceHealth.ProviderRouteDecision
				: SessionConfig.ProviderRouteDecision;
		const FHyperTwistSpeechNormalizedUsageEvent EffectiveUsageEvent =
			ServiceHealth.LatestUsageEvent.IsStructurallyValid()
				? ServiceHealth.LatestUsageEvent
				: SessionConfig.UsageEventTemplate;
		const FHyperTwistSpeechNormalizedCostEvent EffectiveCostEvent =
			ServiceHealth.LatestCostEvent.IsStructurallyValid()
				? ServiceHealth.LatestCostEvent
				: SessionConfig.CostEventTemplate;
		const FHyperTwistSpeechQuotaRateLimitState EffectiveQuotaState =
			ServiceHealth.QuotaRateLimitState.IsStructurallyValid()
				? ServiceHealth.QuotaRateLimitState
				: BuildDefaultSpeechQuotaRateLimitState(
					SessionConfig.UsageCostAccountingProfileDefinition.IsStructurallyValid()
						? SessionConfig.UsageCostAccountingProfileDefinition
						: BuildDefaultSpeechUsageCostAccountingProfile(
							TEXT("speech-usage-cost-accounting-v1")
						),
					EffectiveProfile,
					!EffectiveRouteDecision.SelectedServiceLaneId.IsEmpty()
						? EffectiveRouteDecision.SelectedServiceLaneId
						: TEXT("speech/python-service"),
					TEXT("within-budget"),
					true,
					false,
					false,
					60,
					3600,
					25.0f
				);
		const FString EffectiveError = !LastError.IsEmpty()
			? LastError
			: (!ServiceHealth.LastError.IsEmpty()
				? ServiceHealth.LastError
				: EffectiveRouteDecision.FailureReason);

		ShellState.ActiveProviderProfileId = EffectiveProfile.ProviderProfileId;
		ShellState.ActiveProviderDisplayLabel = !EffectiveProfile.DisplayLabel.IsEmpty()
			? EffectiveProfile.DisplayLabel
			: EffectiveProfile.ProviderProfileId;
		ShellState.ActiveServiceLaneId = !EffectiveRouteDecision.SelectedServiceLaneId.IsEmpty()
			? EffectiveRouteDecision.SelectedServiceLaneId
			: (!SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
				? SessionConfig.OrchestrationProfile.ServiceLaneId
				: TEXT("speech/python-service"));
		ShellState.ActiveRouteStateId = !EffectiveRouteDecision.RouteStateId.IsEmpty()
			? EffectiveRouteDecision.RouteStateId
			: (ServiceHealth.bReady ? TEXT("route-ready") : TEXT("route-health-unknown"));
		ShellState.UsageAggregationWindowId = !EffectiveUsageEvent.AggregationWindowId.IsEmpty()
			? EffectiveUsageEvent.AggregationWindowId
			: TEXT("service-health-window");
		ShellState.CostAggregationWindowId = !EffectiveCostEvent.AggregationWindowId.IsEmpty()
			? EffectiveCostEvent.AggregationWindowId
			: TEXT("service-health-window");
		ShellState.UsageMeterKind = !EffectiveUsageEvent.MeterKind.IsEmpty()
			? EffectiveUsageEvent.MeterKind
			: TEXT("audio-seconds");
		ShellState.CurrencyCode = !EffectiveCostEvent.CurrencyCode.IsEmpty()
			? EffectiveCostEvent.CurrencyCode
			: TEXT("USD");
		ShellState.LatestUsageEventId = !EffectiveUsageEvent.UsageEventId.IsEmpty()
			? EffectiveUsageEvent.UsageEventId
			: TEXT("speech-usage-event/unavailable");
		ShellState.LatestCostEventId = !EffectiveCostEvent.CostEventId.IsEmpty()
			? EffectiveCostEvent.CostEventId
			: TEXT("speech-cost-event/unavailable");
		ShellState.LatestQuotaStateId = !EffectiveQuotaState.QuotaStateId.IsEmpty()
			? EffectiveQuotaState.QuotaStateId
			: TEXT("speech-quota-state/unavailable");
		ShellState.LatestRouteDecisionId = !EffectiveRouteDecision.RouteDecisionId.IsEmpty()
			? EffectiveRouteDecision.RouteDecisionId
			: TEXT("speech-route-decision/unavailable");
		ShellState.DisplayedUsageQuantity = FMath::Max(0.0f, EffectiveUsageEvent.ReportedQuantity);
		ShellState.DisplayedEstimatedCostUsd = FMath::Max(0.0f, EffectiveCostEvent.EstimatedCost);
		ShellState.DisplayedReportedCostUsd = FMath::Max(0.0f, EffectiveCostEvent.ReportedCost);
		ShellState.RemainingEstimatedSpendUsd =
			FMath::Max(0.0f, EffectiveQuotaState.RemainingEstimatedSpendUsd);
		ShellState.RemainingRequestCount = FMath::Max(0, EffectiveQuotaState.RemainingRequestCount);
		ShellState.RemainingAudioSeconds = FMath::Max(0, EffectiveQuotaState.RemainingAudioSeconds);
		ShellState.bDashboardVisible = true;
		ShellState.bProviderSummaryVisible = Profile.bSupportsProviderSummary;
		ShellState.bUsageCardVisible = true;
		ShellState.bCostCardVisible = true;
		ShellState.bQuotaCardVisible = true;
		ShellState.bRouteDiagnosticsVisible = Profile.bSupportsRouteDiagnostics;
		ShellState.bProviderReceiptPosted = EffectiveCostEvent.bHasProviderPostedCharge;
		ShellState.bEstimateBadgeVisible =
			Profile.bSupportsEstimateBadges
			&& (EffectiveUsageEvent.bEstimateOnly || EffectiveCostEvent.bEstimateOnly);
		ShellState.bQuotaKnown = EffectiveQuotaState.bQuotaKnown;
		ShellState.bRateLimited = EffectiveQuotaState.bRateLimited;
		ShellState.bHardBlocked = EffectiveQuotaState.bHardBlocked;
		ShellState.bRouteReady = EffectiveRouteDecision.IsStructurallyValid()
			? EffectiveRouteDecision.bRouteReady
			: ServiceHealth.bReady;
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechUsageCostDashboardIssue();

		ShellState.StatusLine = TEXT("Provider usage and budget posture within current bounds.");
		ShellState.DetailLine = FString::Printf(
			TEXT("%s reports %.2f %s and %.2f %s estimated cost in %s."),
			*ShellState.ActiveProviderDisplayLabel,
			ShellState.DisplayedUsageQuantity,
			*ShellState.UsageMeterKind,
			ShellState.DisplayedEstimatedCostUsd,
			*ShellState.CurrencyCode,
			*ShellState.UsageAggregationWindowId
		);
		ShellState.bEscalationBannerVisible = false;

		if (!ShellState.bRouteReady || !ServiceHealth.bReady || !EffectiveError.IsEmpty())
		{
			FHyperTwistSpeechUsageCostDashboardIssue Issue;
			Issue.IssueId = TEXT("provider-route-degraded");
			Issue.IssueKind = TEXT("route-degraded");
			Issue.StatusLine = TEXT("Provider route requires attention.");
			Issue.DetailLine = EffectiveError.IsEmpty()
				? TEXT("The provider route is not currently ready. Inspect the active route before relying on usage or cost posture.")
				: FString::Printf(
					TEXT("The provider route reported '%s'. Inspect the active route before relying on usage or cost posture."),
					*EffectiveError
				);
			Issue.RecommendedActionId = Profile.RouteInspectActionId;
			AddSpeechUsageCostDashboardIssue(ShellState, Issue);
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
		}

		if (ShellState.bHardBlocked)
		{
			FHyperTwistSpeechUsageCostDashboardIssue Issue;
			Issue.IssueId = TEXT("provider-hard-blocked");
			Issue.IssueKind = TEXT("hard-blocked");
			Issue.StatusLine = TEXT("Provider usage blocked.");
			Issue.DetailLine = FString::Printf(
				TEXT("The quota state is '%s'. Resolve provider budget posture before depending on further provider-backed capture."),
				*EffectiveQuotaState.StateReason
			);
			Issue.RecommendedActionId = Profile.BudgetInspectActionId;
			AddSpeechUsageCostDashboardIssue(ShellState, Issue);
			ShellState.ActiveIssue = Issue;
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
		}
		else if (ShellState.bRateLimited)
		{
			FHyperTwistSpeechUsageCostDashboardIssue Issue;
			Issue.IssueId = TEXT("provider-rate-limited");
			Issue.IssueKind = TEXT("rate-limited");
			Issue.StatusLine = TEXT("Provider rate limit reached.");
			Issue.DetailLine = FString::Printf(
				TEXT("Remaining requests: %d. Remaining audio seconds: %d. Review provider budget posture before more routed capture."),
				ShellState.RemainingRequestCount,
				ShellState.RemainingAudioSeconds
			);
			Issue.RecommendedActionId = Profile.BudgetInspectActionId;
			AddSpeechUsageCostDashboardIssue(ShellState, Issue);
			ShellState.ActiveIssue = Issue;
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
		}
		else if (!ShellState.bQuotaKnown
			&& ShellState.bRouteReady
			&& EffectiveError.IsEmpty()
			&& ServiceHealth.bReady)
		{
			FHyperTwistSpeechUsageCostDashboardIssue Issue;
			Issue.IssueId = TEXT("provider-budget-posture-unknown");
			Issue.IssueKind = TEXT("budget-posture-unknown");
			Issue.StatusLine = TEXT("Provider budget posture unknown.");
			Issue.DetailLine =
				TEXT("Quota and spend snapshots are not confirmed yet. Treat the current dashboard values as routing diagnostics, not settled provider billing.");
			Issue.RecommendedActionId = Profile.BudgetInspectActionId;
			AddSpeechUsageCostDashboardIssue(ShellState, Issue);
			ShellState.ActiveIssue = Issue;
			ShellState.bEscalationBannerVisible = Profile.bSupportsQuotaEscalationBanner;
		}

		if (ShellState.bEstimateBadgeVisible && !ShellState.bProviderReceiptPosted && ShellState.Issues.Num() <= 0)
		{
			ShellState.DetailLine += TEXT(" Current cost remains estimate-only.");
		}

		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechUsageCostDashboardState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		ApplySpeechUsageCostDefaults(EffectiveConfig);
		if (!SessionState.UsageCostDashboardShellState.IsStructurallyValid())
		{
			SessionState.UsageCostDashboardShellState =
				BuildSpeechUsageCostDashboardShellState(EffectiveConfig, &SessionState);
		}

		const FHyperTwistSpeechUsageCostDashboardShellProfile Profile =
			EffectiveConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.UsageCostDashboardShellProfileDefinition
				: BuildDefaultSpeechUsageCostDashboardShellProfile(
					!EffectiveConfig.UsageCostDashboardShellProfileId.IsEmpty()
						? EffectiveConfig.UsageCostDashboardShellProfileId
						: TEXT("speech-provider-usage-cost-dashboard-shell-v1")
				);

		FHyperTwistSpeechUsageCostDashboardShellState& ShellState =
			SessionState.UsageCostDashboardShellState;
		ShellState.DashboardShellProfileId = Profile.DashboardShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechUsageCostDashboardPosture(
			Profile,
			EffectiveConfig,
			SessionState.ServiceHealth,
			SessionState.LastError,
			ShellState
		);

		ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	FString BuildSpeechUsageCostHistorySourceKind(
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		if (!SessionState.LastError.IsEmpty() && !SessionState.ServiceHealth.bReady)
		{
			return TEXT("provider-fallback-health");
		}
		if (!SessionState.bSessionOpen && !SessionState.OpenedAtUtc.IsEmpty())
		{
			return TEXT("session-closed-health");
		}
		if (SessionState.bHasTranscriptResult)
		{
			return TEXT("post-transcript-health");
		}
		if (SessionState.bSessionOpen)
		{
			return TEXT("session-open-health");
		}

		return TEXT("service-health-snapshot");
	}

	FString BuildSpeechUsageCostHistorySignature(
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		const FHyperTwistSpeechUsageCostDashboardShellState& DashboardState,
		const FString& SourceKind
	)
	{
		return FString::Printf(
			TEXT("%s|%s|%s|%s|%s|%s|%s|%d|%d|%d|%d|%d"),
			*SourceKind,
			*DashboardState.LatestUsageEventId,
			*DashboardState.LatestCostEventId,
			*DashboardState.LatestQuotaStateId,
			*DashboardState.LatestRouteDecisionId,
			*DashboardState.ActiveRouteStateId,
			*SessionState.LastError,
			SessionState.SubmittedUtteranceCount,
			SessionState.FinalTranscriptCount,
			DashboardState.bRouteReady ? 1 : 0,
			DashboardState.bQuotaKnown ? 1 : 0,
			SessionState.bSessionOpen ? 1 : 0
		);
	}

	FHyperTwistSpeechUsageCostHistoryEntry BuildSpeechUsageCostHistoryEntry(
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		const FHyperTwistSpeechUsageCostDashboardShellState& DashboardState,
		const FString& SourceKind,
		const int32 EntryOrdinal
	)
	{
		FHyperTwistSpeechUsageCostHistoryEntry Entry;
		const FString EffectiveSessionId =
			!SessionState.ActiveSessionId.IsEmpty()
				? SessionState.ActiveSessionId
				: (!SessionState.SessionConfig.SessionId.IsEmpty()
					? SessionState.SessionConfig.SessionId
					: TEXT("speech-session-default"));
		Entry.HistoryEntryId = FString::Printf(
			TEXT("speech-usage-cost-history/%s/%02d"),
			*EffectiveSessionId,
			FMath::Max(EntryOrdinal, 1)
		);
		Entry.SourceKind = SourceKind;
		Entry.SessionId = EffectiveSessionId;
		Entry.ProviderProfileId = DashboardState.ActiveProviderProfileId;
		Entry.ServiceLaneId = DashboardState.ActiveServiceLaneId;
		Entry.UsageEventId = DashboardState.LatestUsageEventId;
		Entry.CostEventId = DashboardState.LatestCostEventId;
		Entry.QuotaStateId = DashboardState.LatestQuotaStateId;
		Entry.RouteDecisionId = DashboardState.LatestRouteDecisionId;
		Entry.CapturedAtUtc = !SessionState.LastUpdatedAtUtc.IsEmpty()
			? SessionState.LastUpdatedAtUtc
			: FDateTime::UtcNow().ToIso8601();
		Entry.UsageQuantity = DashboardState.DisplayedUsageQuantity;
		Entry.EstimatedCostUsd = DashboardState.DisplayedEstimatedCostUsd;
		Entry.ReportedCostUsd = DashboardState.DisplayedReportedCostUsd;
		Entry.RemainingEstimatedSpendUsd = DashboardState.RemainingEstimatedSpendUsd;
		Entry.RemainingRequestCount = DashboardState.RemainingRequestCount;
		Entry.RemainingAudioSeconds = DashboardState.RemainingAudioSeconds;
		Entry.bEstimateOnly = DashboardState.bEstimateBadgeVisible;
		Entry.bProviderReceiptPosted = DashboardState.bProviderReceiptPosted;
		Entry.bQuotaKnown = DashboardState.bQuotaKnown;
		Entry.bRateLimited = DashboardState.bRateLimited;
		Entry.bHardBlocked = DashboardState.bHardBlocked;
		Entry.bRouteReady = DashboardState.bRouteReady;
		return Entry;
	}

	void AddSpeechUsageCostHistoryExportIssue(
		FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState,
		const FHyperTwistSpeechUsageCostHistoryExportIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void AppendSpeechUsageCostHistoryEntry(
		const FHyperTwistSpeechUsageCostHistoryExportShellProfile& Profile,
		const FString& Signature,
		const FHyperTwistSpeechUsageCostHistoryEntry& Entry,
		FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState
	)
	{
		if (!Entry.IsStructurallyValid() || ShellState.LastRecordedSignature == Signature)
		{
			return;
		}

		ShellState.HistoryEntries.Add(Entry);
		while (ShellState.HistoryEntries.Num() > Profile.RetainedHistoryEntryLimit)
		{
			ShellState.HistoryEntries.RemoveAt(0);
		}
		ShellState.LastRecordedSignature = Signature;
	}

	void ApplySpeechUsageCostHistoryExportPosture(
		const FHyperTwistSpeechUsageCostHistoryExportShellProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState
	)
	{
		const FHyperTwistSpeechUsageCostDashboardShellState& DashboardState =
			SessionState.UsageCostDashboardShellState;
		const FString SourceKind = BuildSpeechUsageCostHistorySourceKind(SessionState);
		ShellState.ActiveProviderProfileId = DashboardState.ActiveProviderProfileId;
		ShellState.ActiveProviderDisplayLabel = DashboardState.ActiveProviderDisplayLabel;
		ShellState.ActiveServiceLaneId = DashboardState.ActiveServiceLaneId;
		ShellState.SelectedHistoryWindowId = !DashboardState.UsageAggregationWindowId.IsEmpty()
			? DashboardState.UsageAggregationWindowId
			: TEXT("current-session");
		ShellState.ExportPreviewFormatId = Profile.ExportSurfaceMode;
		ShellState.bHistoryVisible = Profile.bSupportsHistoryTimeline;
		ShellState.bExportPreviewVisible = Profile.bSupportsExportPreview;

		const FString Signature = BuildSpeechUsageCostHistorySignature(
			SessionState,
			DashboardState,
			SourceKind
		);
		AppendSpeechUsageCostHistoryEntry(
			Profile,
			Signature,
			BuildSpeechUsageCostHistoryEntry(
				SessionState,
				DashboardState,
				SourceKind,
				ShellState.HistoryEntries.Num() + 1
			),
			ShellState
		);

		ShellState.TotalUsageQuantity = 0.0f;
		ShellState.TotalEstimatedCostUsd = 0.0f;
		ShellState.TotalReportedCostUsd = 0.0f;
		ShellState.LowestRemainingEstimatedSpendUsd = 0.0f;
		ShellState.EstimateOnlyEntryCount = 0;
		ShellState.ProviderReceiptEntryCount = 0;
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechUsageCostHistoryExportIssue();

		for (int32 EntryIndex = 0; EntryIndex < ShellState.HistoryEntries.Num(); ++EntryIndex)
		{
			const FHyperTwistSpeechUsageCostHistoryEntry& HistoryEntry = ShellState.HistoryEntries[EntryIndex];
			ShellState.TotalUsageQuantity += HistoryEntry.UsageQuantity;
			ShellState.TotalEstimatedCostUsd += HistoryEntry.EstimatedCostUsd;
			ShellState.TotalReportedCostUsd += HistoryEntry.ReportedCostUsd;
			ShellState.LowestRemainingEstimatedSpendUsd =
				EntryIndex == 0
					? HistoryEntry.RemainingEstimatedSpendUsd
					: FMath::Min(
						ShellState.LowestRemainingEstimatedSpendUsd,
						HistoryEntry.RemainingEstimatedSpendUsd
					);
			if (HistoryEntry.bEstimateOnly)
			{
				++ShellState.EstimateOnlyEntryCount;
			}
			if (HistoryEntry.bProviderReceiptPosted)
			{
				++ShellState.ProviderReceiptEntryCount;
			}
		}

		ShellState.HistoryEntryCount = ShellState.HistoryEntries.Num();
		ShellState.bExportPreviewReady = ShellState.HistoryEntries.Num() > 0;
		ShellState.bCopySummaryReady =
			Profile.bSupportsCopySummary && ShellState.bExportPreviewReady;
		ShellState.bEstimateWatermarkVisible =
			Profile.bSupportsEstimateWatermark && ShellState.EstimateOnlyEntryCount > 0;
		ShellState.LatestSourceKind = SourceKind;
		ShellState.LatestHistoryEntryId = ShellState.HistoryEntries.Num() > 0
			? ShellState.HistoryEntries.Last().HistoryEntryId
			: FString();

		if (ShellState.HistoryEntries.Num() <= 0)
		{
			FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
			Issue.IssueId = TEXT("provider-usage-cost-history-empty");
			Issue.IssueKind = TEXT("no-history");
			Issue.StatusLine = TEXT("Provider usage/cost history not captured yet.");
			Issue.DetailLine =
				TEXT("Refresh the provider usage/cost surfaces before relying on export preview output.");
			Issue.RecommendedActionId = Profile.RefreshActionId;
			AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
		}
		else
		{
			const FHyperTwistSpeechUsageCostHistoryEntry& LatestEntry = ShellState.HistoryEntries.Last();
			ShellState.LatestSourceKind = LatestEntry.SourceKind;

			if (!LatestEntry.bRouteReady || (!SessionState.LastError.IsEmpty() && !SessionState.ServiceHealth.bReady))
			{
				FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
				Issue.IssueId = TEXT("provider-usage-cost-history-route-degraded");
				Issue.IssueKind = TEXT("route-degraded");
				Issue.StatusLine = TEXT("Provider history captured with route degradation.");
				Issue.DetailLine = SessionState.LastError.IsEmpty()
					? TEXT("The latest history snapshot came from a degraded provider route. Review the route before treating export preview output as current operating posture.")
					: FString::Printf(
						TEXT("The latest history snapshot captured '%s'. Review the route before treating export preview output as current operating posture."),
						*SessionState.LastError
					);
				Issue.RecommendedActionId = Profile.RouteInspectActionId;
				AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
			}
			else if (LatestEntry.bHardBlocked)
			{
				FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
				Issue.IssueId = TEXT("provider-usage-cost-history-hard-blocked");
				Issue.IssueKind = TEXT("hard-blocked");
				Issue.StatusLine = TEXT("Provider history shows hard-blocked budget posture.");
				Issue.DetailLine =
					TEXT("The latest history snapshot reflects a hard-blocked provider budget posture. Review budget state before relying on more provider-backed capture.");
				Issue.RecommendedActionId = Profile.BudgetInspectActionId;
				AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
			}
			else if (LatestEntry.bRateLimited)
			{
				FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
				Issue.IssueId = TEXT("provider-usage-cost-history-rate-limited");
				Issue.IssueKind = TEXT("rate-limited");
				Issue.StatusLine = TEXT("Provider history shows rate-limited posture.");
				Issue.DetailLine =
					TEXT("The latest history snapshot reflects a rate-limited provider route. Review budget state before relying on more provider-backed capture.");
				Issue.RecommendedActionId = Profile.BudgetInspectActionId;
				AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
			}

			if (ShellState.ActiveIssue.IsStructurallyValid())
			{
				ShellState.StatusLine = ShellState.ActiveIssue.StatusLine;
				ShellState.DetailLine = ShellState.ActiveIssue.DetailLine;
			}
			else
			{
				ShellState.StatusLine = TEXT("Provider usage/cost history ready for operator preview.");
				ShellState.DetailLine = FString::Printf(
					TEXT("%d snapshots retain %.2f %s and %.2f USD estimated cost for %s."),
					ShellState.HistoryEntryCount,
					ShellState.TotalUsageQuantity,
					*DashboardState.UsageMeterKind,
					ShellState.TotalEstimatedCostUsd,
					*ShellState.ActiveProviderDisplayLabel
				);
			}
		}

		ShellState.ExportPreviewText = FString::Printf(
			TEXT("providerProfileId=%s\nserviceLaneId=%s\nhistoryEntryCount=%d\nlatestSourceKind=%s\ntotalUsageQuantity=%.2f\n")
			TEXT("totalEstimatedCostUsd=%.2f\ntotalReportedCostUsd=%.2f\nestimateOnlyEntryCount=%d\nproviderReceiptEntryCount=%d\n")
			TEXT("lowestRemainingEstimatedSpendUsd=%.2f\nlatestHistoryEntryId=%s\nlastError=%s"),
			*ShellState.ActiveProviderProfileId,
			*ShellState.ActiveServiceLaneId,
			ShellState.HistoryEntryCount,
			*ShellState.LatestSourceKind,
			ShellState.TotalUsageQuantity,
			ShellState.TotalEstimatedCostUsd,
			ShellState.TotalReportedCostUsd,
			ShellState.EstimateOnlyEntryCount,
			ShellState.ProviderReceiptEntryCount,
			ShellState.LowestRemainingEstimatedSpendUsd,
			*ShellState.LatestHistoryEntryId,
			*SessionState.LastError
		);
		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechUsageCostHistoryExportState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		ApplySpeechUsageCostDefaults(EffectiveConfig);
		if (!SessionState.UsageCostHistoryExportShellState.IsStructurallyValid())
		{
			SessionState.UsageCostHistoryExportShellState =
				BuildSpeechUsageCostHistoryExportShellState(EffectiveConfig, &SessionState);
		}

		const FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile =
			EffectiveConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.UsageCostHistoryExportShellProfileDefinition
				: BuildDefaultSpeechUsageCostHistoryExportShellProfile(
					!EffectiveConfig.UsageCostHistoryExportShellProfileId.IsEmpty()
						? EffectiveConfig.UsageCostHistoryExportShellProfileId
						: TEXT("speech-provider-usage-cost-history-export-shell-v1")
				);

		FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState =
			SessionState.UsageCostHistoryExportShellState;
		ShellState.HistoryExportShellProfileId = Profile.HistoryExportShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechUsageCostHistoryExportPosture(Profile, SessionState, ShellState);

		ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ExportPreviewActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.CopySummaryActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	float GetSpeechProviderReceiptVarianceToleranceUsd()
	{
		return 0.01f;
	}

	FString BuildSpeechProviderReceiptReviewSourceKind(
		const FHyperTwistSpeechUsageCostHistoryEntry& HistoryEntry
	)
	{
		if (HistoryEntry.SourceKind.Equals(TEXT("provider-fallback-health"), ESearchCase::IgnoreCase))
		{
			return TEXT("provider-fallback-health");
		}
		if (HistoryEntry.bProviderReceiptPosted)
		{
			return TEXT("provider-posted-charge");
		}
		return TEXT("history-derived-estimate-only");
	}

	FHyperTwistSpeechProviderReceiptReviewEntry BuildSpeechProviderReceiptReviewEntry(
		const FHyperTwistSpeechUsageCostHistoryEntry& HistoryEntry,
		const FString& ChargeWindowId
	)
	{
		FHyperTwistSpeechProviderReceiptReviewEntry Entry;
		Entry.ReceiptEntryId = FString::Printf(
			TEXT("provider-receipt-review/%s"),
			*HistoryEntry.HistoryEntryId
		);
		Entry.SourceKind = BuildSpeechProviderReceiptReviewSourceKind(HistoryEntry);
		Entry.HistoryEntryId = HistoryEntry.HistoryEntryId;
		Entry.UsageEventId = HistoryEntry.UsageEventId;
		Entry.CostEventId = HistoryEntry.CostEventId;
		Entry.ProviderProfileId = HistoryEntry.ProviderProfileId;
		Entry.ServiceLaneId = HistoryEntry.ServiceLaneId;
		Entry.PricingSourceId = HistoryEntry.bProviderReceiptPosted
			? TEXT("provider-posted-charge")
			: TEXT("first-party-estimate");
		Entry.ChargeWindowId = ChargeWindowId.IsEmpty() ? TEXT("current-session") : ChargeWindowId;
		Entry.CapturedAtUtc = HistoryEntry.CapturedAtUtc;
		Entry.EstimatedCostUsd = FMath::Max(0.0f, HistoryEntry.EstimatedCostUsd);
		Entry.ReportedCostUsd = FMath::Max(0.0f, HistoryEntry.ReportedCostUsd);
		Entry.bHasProviderPostedCharge = HistoryEntry.bProviderReceiptPosted;
		Entry.bEstimateOnly = HistoryEntry.bEstimateOnly;
		if (Entry.bHasProviderPostedCharge)
		{
			Entry.AbsoluteVarianceUsd = FMath::Abs(Entry.ReportedCostUsd - Entry.EstimatedCostUsd);
			Entry.bVarianceWithinTolerance =
				Entry.AbsoluteVarianceUsd <= GetSpeechProviderReceiptVarianceToleranceUsd();
			Entry.bRequiresManualInspection = !Entry.bVarianceWithinTolerance;
			if (Entry.bVarianceWithinTolerance)
			{
				Entry.VarianceDirectionId = TEXT("no-variance");
			}
			else
			{
				Entry.VarianceDirectionId = Entry.ReportedCostUsd >= Entry.EstimatedCostUsd
					? TEXT("reported-above-estimate")
					: TEXT("reported-below-estimate");
			}
		}
		else
		{
			Entry.AbsoluteVarianceUsd = 0.0f;
			Entry.VarianceDirectionId = TEXT("provider-charge-pending");
			Entry.bVarianceWithinTolerance = true;
			Entry.bRequiresManualInspection = false;
		}

		return Entry;
	}

	void AddSpeechProviderReceiptReviewIssue(
		FHyperTwistSpeechProviderReceiptReviewShellState& ShellState,
		const FHyperTwistSpeechProviderReceiptReviewIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechProviderReceiptReviewPosture(
		const FHyperTwistSpeechProviderReceiptReviewShellProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechProviderReceiptReviewShellState& ShellState
	)
	{
		ShellState.ActiveProviderProfileId =
			!SessionState.UsageCostHistoryExportShellState.ActiveProviderProfileId.IsEmpty()
				? SessionState.UsageCostHistoryExportShellState.ActiveProviderProfileId
				: (!SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId
					: TEXT("speech-provider/local-http-sidecar-profile-v1"));
		ShellState.ActiveProviderDisplayLabel =
			!SessionState.UsageCostHistoryExportShellState.ActiveProviderDisplayLabel.IsEmpty()
				? SessionState.UsageCostHistoryExportShellState.ActiveProviderDisplayLabel
				: (!SessionState.SessionConfig.ProviderProfileDefinition.DisplayLabel.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileDefinition.DisplayLabel
					: TEXT("Local HTTP Speech Sidecar"));
		ShellState.ActiveServiceLaneId =
			!SessionState.UsageCostHistoryExportShellState.ActiveServiceLaneId.IsEmpty()
				? SessionState.UsageCostHistoryExportShellState.ActiveServiceLaneId
				: (!SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
					? SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId
					: TEXT("speech/python-service"));
		ShellState.SelectedChargeWindowId =
			!SessionState.UsageCostHistoryExportShellState.SelectedHistoryWindowId.IsEmpty()
				? SessionState.UsageCostHistoryExportShellState.SelectedHistoryWindowId
				: TEXT("current-session");
		ShellState.PostedChargeInspectionModeId = Profile.ReceiptSurfaceMode;
		ShellState.bReceiptTimelineVisible = Profile.bSupportsReceiptTimeline;
		ShellState.bPostedChargeSummaryVisible = Profile.bSupportsPostedChargeInspection;
		ShellState.bVarianceReviewVisible = Profile.bSupportsVarianceReview;
		ShellState.ReceiptEntries.Reset();
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechProviderReceiptReviewIssue();
		ShellState.ReceiptEntryCount = 0;
		ShellState.ProviderPostedChargeCount = 0;
		ShellState.EstimateOnlyEntryCount = 0;
		ShellState.VarianceReviewEntryCount = 0;
		ShellState.TotalEstimatedCostUsd = 0.0f;
		ShellState.TotalReportedCostUsd = 0.0f;
		ShellState.TotalAbsoluteVarianceUsd = 0.0f;
		ShellState.HighestAbsoluteVarianceUsd = 0.0f;
		ShellState.LatestReceiptEntryId.Reset();
		ShellState.bReceiptSummaryReady = false;
		ShellState.bPostedChargeInspectionReady = false;
		ShellState.bVarianceReviewReady = false;

		const FHyperTwistSpeechUsageCostHistoryExportShellState& HistoryState =
			SessionState.UsageCostHistoryExportShellState;
		if (!HistoryState.IsStructurallyValid() || HistoryState.HistoryEntries.Num() <= 0)
		{
			FHyperTwistSpeechProviderReceiptReviewIssue Issue;
			Issue.IssueId = TEXT("provider-receipt-review-history-missing");
			Issue.IssueKind = TEXT("no-history");
			Issue.StatusLine = TEXT("Provider receipt review is waiting for usage/cost history.");
			Issue.DetailLine = TEXT("Refresh the retained provider usage/cost history before receipt review begins.");
			Issue.RecommendedActionId = Profile.RefreshActionId;
			Issue.bRequiresOperatorAttention = false;
			AddSpeechProviderReceiptReviewIssue(ShellState, Issue);
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.ActiveIssueCount = ShellState.Issues.Num();
			return;
		}

		const int32 ReceiptLimit = FMath::Max(1, Profile.RetainedReceiptEntryLimit);
		const int32 StartIndex = FMath::Max(0, HistoryState.HistoryEntries.Num() - ReceiptLimit);
		for (int32 EntryIndex = StartIndex; EntryIndex < HistoryState.HistoryEntries.Num(); ++EntryIndex)
		{
			const FHyperTwistSpeechUsageCostHistoryEntry& HistoryEntry = HistoryState.HistoryEntries[EntryIndex];
			if (!HistoryEntry.IsStructurallyValid())
			{
				continue;
			}

			const FHyperTwistSpeechProviderReceiptReviewEntry Entry =
				BuildSpeechProviderReceiptReviewEntry(HistoryEntry, ShellState.SelectedChargeWindowId);
			ShellState.ReceiptEntries.Add(Entry);
			ShellState.LatestReceiptEntryId = Entry.ReceiptEntryId;
			ShellState.LatestSourceKind = Entry.SourceKind;
			ShellState.TotalEstimatedCostUsd += Entry.EstimatedCostUsd;
			ShellState.TotalReportedCostUsd += Entry.ReportedCostUsd;
			ShellState.TotalAbsoluteVarianceUsd += Entry.AbsoluteVarianceUsd;
			ShellState.HighestAbsoluteVarianceUsd =
				FMath::Max(ShellState.HighestAbsoluteVarianceUsd, Entry.AbsoluteVarianceUsd);
			if (Entry.bHasProviderPostedCharge)
			{
				++ShellState.ProviderPostedChargeCount;
			}
			if (Entry.bEstimateOnly)
			{
				++ShellState.EstimateOnlyEntryCount;
			}
			if (Entry.bRequiresManualInspection)
			{
				++ShellState.VarianceReviewEntryCount;
			}
		}

		ShellState.ReceiptEntryCount = ShellState.ReceiptEntries.Num();
		ShellState.bReceiptSummaryReady = ShellState.ReceiptEntryCount > 0;
		ShellState.bPostedChargeInspectionReady =
			Profile.bSupportsPostedChargeInspection && ShellState.ReceiptEntryCount > 0;
		ShellState.bVarianceReviewReady =
			Profile.bSupportsVarianceReview && ShellState.ReceiptEntryCount > 0;

		if (HistoryState.ActiveIssue.IsStructurallyValid()
			&& (HistoryState.ActiveIssue.IssueKind.Equals(TEXT("route-degraded"), ESearchCase::IgnoreCase)
				|| HistoryState.ActiveIssue.IssueKind.Equals(TEXT("hard-blocked"), ESearchCase::IgnoreCase)
				|| HistoryState.ActiveIssue.IssueKind.Equals(TEXT("rate-limited"), ESearchCase::IgnoreCase)
				|| HistoryState.ActiveIssue.IssueKind.Equals(TEXT("no-history"), ESearchCase::IgnoreCase)))
		{
			FHyperTwistSpeechProviderReceiptReviewIssue Issue;
			Issue.IssueId = FString::Printf(
				TEXT("provider-receipt-review-%s"),
				*HistoryState.ActiveIssue.IssueKind
			);
			Issue.IssueKind = HistoryState.ActiveIssue.IssueKind;
			Issue.StatusLine = HistoryState.ActiveIssue.StatusLine;
			Issue.DetailLine = HistoryState.ActiveIssue.DetailLine;
			Issue.RecommendedActionId = HistoryState.ActiveIssue.RecommendedActionId;
			Issue.bRequiresOperatorAttention = HistoryState.ActiveIssue.bRequiresOperatorAttention;
			AddSpeechProviderReceiptReviewIssue(ShellState, Issue);
		}
		else if (ShellState.VarianceReviewEntryCount > 0)
		{
			FHyperTwistSpeechProviderReceiptReviewIssue Issue;
			Issue.IssueId = TEXT("provider-receipt-review-variance-detected");
			Issue.IssueKind = TEXT("variance-detected");
			Issue.StatusLine = TEXT("Provider posted-charge variance requires review.");
			Issue.DetailLine = TEXT("At least one posted provider charge diverges from the first-party estimate beyond the bounded review tolerance.");
			Issue.RecommendedActionId = Profile.VarianceReviewActionId;
			Issue.bRequiresOperatorAttention = true;
			AddSpeechProviderReceiptReviewIssue(ShellState, Issue);
		}
		else if (ShellState.ProviderPostedChargeCount <= 0)
		{
			FHyperTwistSpeechProviderReceiptReviewIssue Issue;
			Issue.IssueId = TEXT("provider-receipt-review-charge-pending");
			Issue.IssueKind = TEXT("provider-charge-pending");
			Issue.StatusLine = TEXT("Provider posted charges have not appeared yet.");
			Issue.DetailLine = TEXT("Receipt review is bounded and ready, but the current retained snapshots still show estimate-only posture rather than a provider-posted charge.");
			Issue.RecommendedActionId = Profile.PostedChargeInspectActionId;
			Issue.bRequiresOperatorAttention = false;
			AddSpeechProviderReceiptReviewIssue(ShellState, Issue);
		}

		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.StatusLine = ShellState.ActiveIssue.StatusLine;
			ShellState.DetailLine = ShellState.ActiveIssue.DetailLine;
		}
		else if (ShellState.ProviderPostedChargeCount > 0)
		{
			ShellState.StatusLine = TEXT("Posted provider charges are ready for inspection.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d posted charges are available for bounded comparison against first-party estimates for %s."),
				ShellState.ProviderPostedChargeCount,
				*ShellState.ActiveProviderDisplayLabel
			);
		}
		else
		{
			ShellState.StatusLine = TEXT("Provider receipt review is ready for bounded inspection.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d retained snapshots are available for %s, but provider-posted charges have not appeared yet."),
				ShellState.ReceiptEntryCount,
				*ShellState.ActiveProviderDisplayLabel
			);
		}

		ShellState.ReceiptSummaryText = FString::Printf(
			TEXT("providerProfileId=%s\nserviceLaneId=%s\nreceiptEntryCount=%d\nproviderPostedChargeCount=%d\n")
			TEXT("estimateOnlyEntryCount=%d\nvarianceReviewEntryCount=%d\ntotalEstimatedCostUsd=%.2f\n")
			TEXT("totalReportedCostUsd=%.2f\ntotalAbsoluteVarianceUsd=%.2f\nhighestAbsoluteVarianceUsd=%.2f\n")
			TEXT("latestReceiptEntryId=%s\nlatestSourceKind=%s\nlastError=%s"),
			*ShellState.ActiveProviderProfileId,
			*ShellState.ActiveServiceLaneId,
			ShellState.ReceiptEntryCount,
			ShellState.ProviderPostedChargeCount,
			ShellState.EstimateOnlyEntryCount,
			ShellState.VarianceReviewEntryCount,
			ShellState.TotalEstimatedCostUsd,
			ShellState.TotalReportedCostUsd,
			ShellState.TotalAbsoluteVarianceUsd,
			ShellState.HighestAbsoluteVarianceUsd,
			*ShellState.LatestReceiptEntryId,
			*ShellState.LatestSourceKind,
			*SessionState.LastError
		);
		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechProviderReceiptReviewState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		ApplySpeechUsageCostDefaults(EffectiveConfig);
		if (!SessionState.UsageCostHistoryExportShellState.IsStructurallyValid())
		{
			SessionState.UsageCostHistoryExportShellState =
				BuildSpeechUsageCostHistoryExportShellState(EffectiveConfig, &SessionState);
		}

		const FHyperTwistSpeechProviderReceiptReviewShellProfile Profile =
			EffectiveConfig.ProviderReceiptReviewShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.ProviderReceiptReviewShellProfileDefinition
				: BuildDefaultSpeechProviderReceiptReviewShellProfile(
					!EffectiveConfig.ProviderReceiptReviewShellProfileId.IsEmpty()
						? EffectiveConfig.ProviderReceiptReviewShellProfileId
						: TEXT("speech-provider-receipt-review-shell-v1")
				);

		if (!SessionState.ProviderReceiptReviewShellState.IsStructurallyValid())
		{
			SessionState.ProviderReceiptReviewShellState =
				BuildSpeechProviderReceiptReviewShellState(EffectiveConfig, &SessionState);
		}

		FHyperTwistSpeechProviderReceiptReviewShellState& ShellState =
			SessionState.ProviderReceiptReviewShellState;
		ShellState.ReceiptReviewShellProfileId = Profile.ReceiptReviewShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechProviderReceiptReviewPosture(Profile, SessionState, ShellState);

		ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.PostedChargeInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.VarianceReviewActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	FString BuildSpeechProviderBillingSettlementSourceKind(
		const FHyperTwistSpeechProviderReceiptReviewEntry& ReceiptEntry
	)
	{
		if (ReceiptEntry.SourceKind.Contains(TEXT("fallback"), ESearchCase::IgnoreCase))
		{
			return TEXT("receipt-review-fallback-health");
		}

		if (ReceiptEntry.bHasProviderPostedCharge)
		{
			return TEXT("receipt-review-derived-posted-charge");
		}

		if (ReceiptEntry.bEstimateOnly)
		{
			return TEXT("receipt-review-derived-estimate-only");
		}

		return TEXT("receipt-review-derived-mixed");
	}

	FHyperTwistSpeechProviderBillingSettlementEntry BuildSpeechProviderBillingSettlementEntry(
		const FHyperTwistSpeechProviderReceiptReviewEntry& ReceiptEntry,
		const FString& SettlementWindowId
	)
	{
		FHyperTwistSpeechProviderBillingSettlementEntry Entry;
		Entry.SettlementEntryId = FString::Printf(
			TEXT("speech-provider-settlement-entry/%s"),
			*ReceiptEntry.ReceiptEntryId
		);
		Entry.SourceKind = BuildSpeechProviderBillingSettlementSourceKind(ReceiptEntry);
		Entry.ReceiptEntryId = ReceiptEntry.ReceiptEntryId;
		Entry.HistoryEntryId = ReceiptEntry.HistoryEntryId;
		Entry.ProviderProfileId = ReceiptEntry.ProviderProfileId;
		Entry.ServiceLaneId = ReceiptEntry.ServiceLaneId;
		Entry.PricingSourceId = ReceiptEntry.PricingSourceId;
		Entry.ChargeWindowId = ReceiptEntry.ChargeWindowId;
		Entry.SettlementWindowId = SettlementWindowId.IsEmpty()
			? TEXT("current-session")
			: SettlementWindowId;
		Entry.CapturedAtUtc = ReceiptEntry.CapturedAtUtc;
		Entry.EstimatedCostUsd = ReceiptEntry.EstimatedCostUsd;
		Entry.ReportedCostUsd = ReceiptEntry.ReportedCostUsd;
		Entry.SettlementDeltaUsd = ReceiptEntry.AbsoluteVarianceUsd;
		Entry.bHasProviderPostedCharge = ReceiptEntry.bHasProviderPostedCharge;
		Entry.bRequiresManualReview =
			ReceiptEntry.bHasProviderPostedCharge && !ReceiptEntry.bVarianceWithinTolerance;
		Entry.bInvoiceReconciliationReady =
			ReceiptEntry.bHasProviderPostedCharge && !Entry.bRequiresManualReview;
		Entry.bSettlementBlocked = !Entry.bInvoiceReconciliationReady;

		if (!ReceiptEntry.bHasProviderPostedCharge)
		{
			Entry.SettlementStateId = TEXT("awaiting-provider-posted-charge");
			Entry.InvoiceReconciliationStateId = TEXT("invoice-pending");
		}
		else if (Entry.bRequiresManualReview)
		{
			Entry.SettlementStateId = TEXT("variance-review-required");
			Entry.InvoiceReconciliationStateId = TEXT("invoice-variance-review-required");
		}
		else
		{
			Entry.SettlementStateId = TEXT("ready-for-settlement-review");
			Entry.InvoiceReconciliationStateId = TEXT("invoice-ready-for-reconciliation");
		}

		return Entry;
	}

	void AddSpeechProviderBillingSettlementIssue(
		FHyperTwistSpeechProviderBillingSettlementShellState& ShellState,
		const FHyperTwistSpeechProviderBillingSettlementIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechProviderBillingSettlementPosture(
		const FHyperTwistSpeechProviderBillingSettlementShellProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechProviderBillingSettlementShellState& ShellState
	)
	{
		ShellState.ActiveProviderProfileId =
			!SessionState.ProviderReceiptReviewShellState.ActiveProviderProfileId.IsEmpty()
				? SessionState.ProviderReceiptReviewShellState.ActiveProviderProfileId
				: (!SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId
					: TEXT("speech-provider/local-http-sidecar-profile-v1"));
		ShellState.ActiveProviderDisplayLabel =
			!SessionState.ProviderReceiptReviewShellState.ActiveProviderDisplayLabel.IsEmpty()
				? SessionState.ProviderReceiptReviewShellState.ActiveProviderDisplayLabel
				: (!SessionState.SessionConfig.ProviderProfileDefinition.DisplayLabel.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileDefinition.DisplayLabel
					: TEXT("Local HTTP Speech Sidecar"));
		ShellState.ActiveServiceLaneId =
			!SessionState.ProviderReceiptReviewShellState.ActiveServiceLaneId.IsEmpty()
				? SessionState.ProviderReceiptReviewShellState.ActiveServiceLaneId
				: (!SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
					? SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId
					: TEXT("speech/python-service"));
		ShellState.SelectedSettlementWindowId =
			!SessionState.ProviderReceiptReviewShellState.SelectedChargeWindowId.IsEmpty()
				? SessionState.ProviderReceiptReviewShellState.SelectedChargeWindowId
				: TEXT("current-session");
		ShellState.SettlementSurfaceModeId = Profile.SettlementSurfaceMode;
		ShellState.InvoiceReconciliationModeId = Profile.InvoiceReconciliationMode;
		ShellState.bSettlementTimelineVisible = Profile.bSupportsSettlementTimeline;
		ShellState.bInvoiceReconciliationVisible = Profile.bSupportsInvoiceReconciliation;
		ShellState.bSettlementReadinessVisible = Profile.bSupportsSettlementReadinessReview;
		ShellState.SettlementEntries.Reset();
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechProviderBillingSettlementIssue();
		ShellState.SettlementEntryCount = 0;
		ShellState.ProviderPostedChargeCount = 0;
		ShellState.ReconciliationReadyEntryCount = 0;
		ShellState.EstimateOnlyEntryCount = 0;
		ShellState.ManualReviewEntryCount = 0;
		ShellState.BlockedSettlementEntryCount = 0;
		ShellState.TotalEstimatedCostUsd = 0.0f;
		ShellState.TotalReportedCostUsd = 0.0f;
		ShellState.TotalSettlementDeltaUsd = 0.0f;
		ShellState.HighestSettlementDeltaUsd = 0.0f;
		ShellState.LatestSettlementEntryId.Reset();
		ShellState.bSettlementSummaryReady = false;
		ShellState.bInvoiceReconciliationReady = false;
		ShellState.bSettlementReadinessReviewReady = false;

		const FHyperTwistSpeechProviderReceiptReviewShellState& ReceiptState =
			SessionState.ProviderReceiptReviewShellState;
		if (!ReceiptState.IsStructurallyValid() || ReceiptState.ReceiptEntries.Num() <= 0)
		{
			FHyperTwistSpeechProviderBillingSettlementIssue Issue;
			Issue.IssueId = TEXT("provider-billing-settlement-receipt-review-missing");
			Issue.IssueKind = TEXT("no-receipt-review");
			Issue.StatusLine = TEXT("Provider billing settlement is waiting for receipt review.");
			Issue.DetailLine = TEXT("Refresh the retained provider receipt-review shell before settlement posture begins.");
			Issue.RecommendedActionId = Profile.RefreshActionId;
			Issue.bRequiresOperatorAttention = false;
			AddSpeechProviderBillingSettlementIssue(ShellState, Issue);
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.ActiveIssueCount = ShellState.Issues.Num();
			return;
		}

		const int32 SettlementLimit = FMath::Max(1, Profile.RetainedSettlementEntryLimit);
		const int32 StartIndex = FMath::Max(0, ReceiptState.ReceiptEntries.Num() - SettlementLimit);
		for (int32 EntryIndex = StartIndex; EntryIndex < ReceiptState.ReceiptEntries.Num(); ++EntryIndex)
		{
			const FHyperTwistSpeechProviderReceiptReviewEntry& ReceiptEntry =
				ReceiptState.ReceiptEntries[EntryIndex];
			if (!ReceiptEntry.IsStructurallyValid())
			{
				continue;
			}

			const FHyperTwistSpeechProviderBillingSettlementEntry Entry =
				BuildSpeechProviderBillingSettlementEntry(
					ReceiptEntry,
					ShellState.SelectedSettlementWindowId
				);
			ShellState.SettlementEntries.Add(Entry);
			ShellState.LatestSettlementEntryId = Entry.SettlementEntryId;
			ShellState.LatestSourceKind = Entry.SourceKind;
			ShellState.TotalEstimatedCostUsd += Entry.EstimatedCostUsd;
			ShellState.TotalReportedCostUsd += Entry.ReportedCostUsd;
			ShellState.TotalSettlementDeltaUsd += Entry.SettlementDeltaUsd;
			ShellState.HighestSettlementDeltaUsd =
				FMath::Max(ShellState.HighestSettlementDeltaUsd, Entry.SettlementDeltaUsd);
			if (Entry.bHasProviderPostedCharge)
			{
				++ShellState.ProviderPostedChargeCount;
			}
			if (Entry.bInvoiceReconciliationReady)
			{
				++ShellState.ReconciliationReadyEntryCount;
			}
			if (ReceiptEntry.bEstimateOnly)
			{
				++ShellState.EstimateOnlyEntryCount;
			}
			if (Entry.bRequiresManualReview)
			{
				++ShellState.ManualReviewEntryCount;
			}
			if (Entry.bSettlementBlocked)
			{
				++ShellState.BlockedSettlementEntryCount;
			}
		}

		ShellState.SettlementEntryCount = ShellState.SettlementEntries.Num();
		ShellState.bSettlementSummaryReady = ShellState.SettlementEntryCount > 0;
		ShellState.bInvoiceReconciliationReady =
			Profile.bSupportsInvoiceReconciliation
			&& ShellState.ReconciliationReadyEntryCount > 0;
		ShellState.bSettlementReadinessReviewReady =
			Profile.bSupportsSettlementReadinessReview
			&& ShellState.SettlementEntryCount > 0;

		if (ReceiptState.ActiveIssue.IsStructurallyValid()
			&& (ReceiptState.ActiveIssue.IssueKind.Equals(TEXT("route-degraded"), ESearchCase::IgnoreCase)
				|| ReceiptState.ActiveIssue.IssueKind.Equals(TEXT("hard-blocked"), ESearchCase::IgnoreCase)
				|| ReceiptState.ActiveIssue.IssueKind.Equals(TEXT("rate-limited"), ESearchCase::IgnoreCase)
				|| ReceiptState.ActiveIssue.IssueKind.Equals(TEXT("no-history"), ESearchCase::IgnoreCase)))
		{
			FHyperTwistSpeechProviderBillingSettlementIssue Issue;
			Issue.IssueId = FString::Printf(
				TEXT("provider-billing-settlement-%s"),
				*ReceiptState.ActiveIssue.IssueKind
			);
			Issue.IssueKind = ReceiptState.ActiveIssue.IssueKind;
			Issue.StatusLine = ReceiptState.ActiveIssue.StatusLine;
			Issue.DetailLine = ReceiptState.ActiveIssue.DetailLine;
			Issue.RecommendedActionId = ReceiptState.ActiveIssue.RecommendedActionId;
			Issue.bRequiresOperatorAttention =
				ReceiptState.ActiveIssue.bRequiresOperatorAttention;
			AddSpeechProviderBillingSettlementIssue(ShellState, Issue);
		}
		else if (ShellState.ManualReviewEntryCount > 0)
		{
			FHyperTwistSpeechProviderBillingSettlementIssue Issue;
			Issue.IssueId = TEXT("provider-billing-settlement-variance-review-required");
			Issue.IssueKind = TEXT("settlement-variance-review-required");
			Issue.StatusLine = TEXT("Settlement variance requires review before reconciliation.");
			Issue.DetailLine = TEXT("At least one posted provider charge still diverges from the first-party estimate beyond the bounded receipt-review tolerance.");
			Issue.RecommendedActionId = Profile.SettlementReadinessActionId;
			Issue.bRequiresOperatorAttention = true;
			AddSpeechProviderBillingSettlementIssue(ShellState, Issue);
		}
		else if (ShellState.ProviderPostedChargeCount <= 0)
		{
			FHyperTwistSpeechProviderBillingSettlementIssue Issue;
			Issue.IssueId = TEXT("provider-billing-settlement-charge-pending");
			Issue.IssueKind = TEXT("provider-charge-pending");
			Issue.StatusLine = TEXT("Provider billing settlement is waiting for posted charges.");
			Issue.DetailLine = TEXT("Settlement posture is bounded and ready, but the retained receipt review still shows estimate-only provider cost posture.");
			Issue.RecommendedActionId = Profile.InvoiceReconciliationActionId;
			Issue.bRequiresOperatorAttention = false;
			AddSpeechProviderBillingSettlementIssue(ShellState, Issue);
		}

		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.StatusLine = ShellState.ActiveIssue.StatusLine;
			ShellState.DetailLine = ShellState.ActiveIssue.DetailLine;
		}
		else if (ShellState.ReconciliationReadyEntryCount > 0)
		{
			ShellState.StatusLine =
				TEXT("Provider billing settlement is ready for bounded reconciliation.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d retained posted charges for %s are within the current first-party tolerance and ready for invoice reconciliation review."),
				ShellState.ReconciliationReadyEntryCount,
				*ShellState.ActiveProviderDisplayLabel
			);
		}
		else
		{
			ShellState.StatusLine =
				TEXT("Provider billing settlement remains bounded above receipt review.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d retained settlement entries are available for %s, but a reconciled provider invoice posture is not ready yet."),
				ShellState.SettlementEntryCount,
				*ShellState.ActiveProviderDisplayLabel
			);
		}

		ShellState.SettlementSummaryText = FString::Printf(
			TEXT("providerProfileId=%s\nserviceLaneId=%s\nsettlementEntryCount=%d\nproviderPostedChargeCount=%d\n")
			TEXT("reconciliationReadyEntryCount=%d\nestimateOnlyEntryCount=%d\nmanualReviewEntryCount=%d\n")
			TEXT("blockedSettlementEntryCount=%d\ntotalEstimatedCostUsd=%.2f\ntotalReportedCostUsd=%.2f\n")
			TEXT("totalSettlementDeltaUsd=%.2f\nhighestSettlementDeltaUsd=%.2f\nlatestSettlementEntryId=%s\n")
			TEXT("latestSourceKind=%s\nlastError=%s"),
			*ShellState.ActiveProviderProfileId,
			*ShellState.ActiveServiceLaneId,
			ShellState.SettlementEntryCount,
			ShellState.ProviderPostedChargeCount,
			ShellState.ReconciliationReadyEntryCount,
			ShellState.EstimateOnlyEntryCount,
			ShellState.ManualReviewEntryCount,
			ShellState.BlockedSettlementEntryCount,
			ShellState.TotalEstimatedCostUsd,
			ShellState.TotalReportedCostUsd,
			ShellState.TotalSettlementDeltaUsd,
			ShellState.HighestSettlementDeltaUsd,
			*ShellState.LatestSettlementEntryId,
			*ShellState.LatestSourceKind,
			*SessionState.LastError
		);
		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechProviderBillingSettlementState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		ApplySpeechUsageCostDefaults(EffectiveConfig);
		if (!SessionState.ProviderReceiptReviewShellState.IsStructurallyValid())
		{
			SessionState.ProviderReceiptReviewShellState =
				BuildSpeechProviderReceiptReviewShellState(EffectiveConfig, &SessionState);
		}

		const FHyperTwistSpeechProviderBillingSettlementShellProfile Profile =
			EffectiveConfig.ProviderBillingSettlementShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.ProviderBillingSettlementShellProfileDefinition
				: BuildDefaultSpeechProviderBillingSettlementShellProfile(
					!EffectiveConfig.ProviderBillingSettlementShellProfileId.IsEmpty()
						? EffectiveConfig.ProviderBillingSettlementShellProfileId
						: TEXT("speech-provider-billing-settlement-shell-v1")
				);

		if (!SessionState.ProviderBillingSettlementShellState.IsStructurallyValid())
		{
			SessionState.ProviderBillingSettlementShellState =
				BuildSpeechProviderBillingSettlementShellState(EffectiveConfig, &SessionState);
		}

		FHyperTwistSpeechProviderBillingSettlementShellState& ShellState =
			SessionState.ProviderBillingSettlementShellState;
		ShellState.BillingSettlementShellProfileId = Profile.BillingSettlementShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechProviderBillingSettlementPosture(Profile, SessionState, ShellState);

		ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.InvoiceReconciliationActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.SettlementReadinessActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	FString BuildSpeechProviderSettlementExceptionSourceKind(
		const FHyperTwistSpeechProviderBillingSettlementEntry& SettlementEntry
	)
	{
		if (SettlementEntry.SourceKind.Contains(TEXT("fallback"), ESearchCase::IgnoreCase))
		{
			return TEXT("settlement-fallback-health");
		}

		if (!SettlementEntry.bHasProviderPostedCharge)
		{
			return TEXT("settlement-derived-pending-charge");
		}

		if (SettlementEntry.bRequiresManualReview)
		{
			return TEXT("settlement-derived-variance-review");
		}

		if (SettlementEntry.bSettlementBlocked)
		{
			return TEXT("settlement-derived-blocked");
		}

		return TEXT("settlement-derived-ready");
	}

	FHyperTwistSpeechProviderSettlementExceptionEntry
	BuildSpeechProviderSettlementExceptionEntry(
		const FHyperTwistSpeechProviderBillingSettlementEntry& SettlementEntry,
		const FString& SelectedSettlementWindowId
	)
	{
		FHyperTwistSpeechProviderSettlementExceptionEntry Entry;
		Entry.ExceptionEntryId = FString::Printf(
			TEXT("speech-provider-settlement-exception/%s"),
			*SettlementEntry.SettlementEntryId
		);
		Entry.SourceKind = BuildSpeechProviderSettlementExceptionSourceKind(SettlementEntry);
		Entry.SettlementEntryId = SettlementEntry.SettlementEntryId;
		Entry.ReceiptEntryId = SettlementEntry.ReceiptEntryId;
		Entry.HistoryEntryId = SettlementEntry.HistoryEntryId;
		Entry.ProviderProfileId = SettlementEntry.ProviderProfileId;
		Entry.ServiceLaneId = SettlementEntry.ServiceLaneId;
		Entry.CapturedAtUtc = SettlementEntry.CapturedAtUtc;
		Entry.EstimatedCostUsd = SettlementEntry.EstimatedCostUsd;
		Entry.ReportedCostUsd = SettlementEntry.ReportedCostUsd;
		Entry.SettlementDeltaUsd = SettlementEntry.SettlementDeltaUsd;
		Entry.bRequiresManualReview = SettlementEntry.bRequiresManualReview;
		Entry.bSettlementBlocked = SettlementEntry.bSettlementBlocked;
		Entry.HandoffStateId = TEXT("handoff-not-required");

		if (Entry.SourceKind.Equals(TEXT("settlement-fallback-health"), ESearchCase::IgnoreCase))
		{
			Entry.ExceptionKindId = TEXT("route-degraded");
			Entry.HandoffStateId = TEXT("handoff-ready-for-route-escalation");
			Entry.bExternalPortalHandoffReady = true;
			Entry.bRequiresOperatorAttention = true;
		}
		else if (!SettlementEntry.bHasProviderPostedCharge)
		{
			Entry.ExceptionKindId = TEXT("provider-charge-pending");
			Entry.HandoffStateId = TEXT("handoff-deferred-until-provider-posted-charge");
			Entry.bExternalPortalHandoffReady = false;
			Entry.bRequiresOperatorAttention = false;
		}
		else if (SettlementEntry.bRequiresManualReview)
		{
			Entry.ExceptionKindId = TEXT("settlement-variance-review-required");
			Entry.HandoffStateId = TEXT("handoff-ready-for-provider-reference");
			Entry.bExternalPortalHandoffReady = true;
			Entry.bRequiresOperatorAttention = true;
		}
		else
		{
			Entry.ExceptionKindId = TEXT("settlement-blocked");
			Entry.HandoffStateId = TEXT("handoff-ready-for-first-party-review");
			Entry.bExternalPortalHandoffReady = true;
			Entry.bRequiresOperatorAttention = SettlementEntry.bSettlementBlocked;
		}

		if (!SelectedSettlementWindowId.IsEmpty())
		{
			Entry.HandoffTargetId = TEXT("external-provider-portal");
		}

		return Entry;
	}

	void AddSpeechProviderSettlementExceptionIssue(
		FHyperTwistSpeechProviderSettlementExceptionShellState& ShellState,
		const FHyperTwistSpeechProviderSettlementExceptionIssue& Issue
	)
	{
		if (!Issue.IsStructurallyValid())
		{
			return;
		}

		ShellState.Issues.Add(Issue);
		if (!ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.ActiveIssue = Issue;
		}
	}

	void ApplySpeechProviderSettlementExceptionPosture(
		const FHyperTwistSpeechProviderSettlementExceptionShellProfile& Profile,
		const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
		FHyperTwistSpeechProviderSettlementExceptionShellState& ShellState
	)
	{
		ShellState.ActiveProviderProfileId =
			!SessionState.ProviderBillingSettlementShellState.ActiveProviderProfileId.IsEmpty()
				? SessionState.ProviderBillingSettlementShellState.ActiveProviderProfileId
				: (!SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileDefinition.ProviderProfileId
					: TEXT("speech-provider/local-http-sidecar-profile-v1"));
		ShellState.ActiveProviderDisplayLabel =
			!SessionState.ProviderBillingSettlementShellState.ActiveProviderDisplayLabel.IsEmpty()
				? SessionState.ProviderBillingSettlementShellState.ActiveProviderDisplayLabel
				: (!SessionState.SessionConfig.ProviderProfileDefinition.DisplayLabel.IsEmpty()
					? SessionState.SessionConfig.ProviderProfileDefinition.DisplayLabel
					: TEXT("Local HTTP Speech Sidecar"));
		ShellState.ActiveServiceLaneId =
			!SessionState.ProviderBillingSettlementShellState.ActiveServiceLaneId.IsEmpty()
				? SessionState.ProviderBillingSettlementShellState.ActiveServiceLaneId
				: (!SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
					? SessionState.SessionConfig.OrchestrationProfile.ServiceLaneId
					: TEXT("speech/python-service"));
		ShellState.SelectedSettlementWindowId =
			!SessionState.ProviderBillingSettlementShellState.SelectedSettlementWindowId.IsEmpty()
				? SessionState.ProviderBillingSettlementShellState.SelectedSettlementWindowId
				: TEXT("current-session");
		ShellState.ExceptionSurfaceModeId = Profile.ExceptionSurfaceMode;
		ShellState.ExternalPortalHandoffModeId = Profile.ExternalPortalHandoffMode;
		ShellState.bExceptionTimelineVisible = Profile.bSupportsExceptionTimeline;
		ShellState.bExternalPortalHandoffVisible = Profile.bSupportsExternalPortalHandoff;
		ShellState.bExceptionReviewVisible = Profile.bSupportsSettlementExceptionReview;
		ShellState.ExceptionEntries.Reset();
		ShellState.Issues.Reset();
		ShellState.ActiveIssue = FHyperTwistSpeechProviderSettlementExceptionIssue();
		ShellState.ExceptionEntryCount = 0;
		ShellState.ExternalPortalHandoffReadyEntryCount = 0;
		ShellState.PendingChargeEntryCount = 0;
		ShellState.ManualReviewEntryCount = 0;
		ShellState.RouteDegradedEntryCount = 0;
		ShellState.BlockedSettlementEntryCount = 0;
		ShellState.TotalEstimatedCostUsd = 0.0f;
		ShellState.TotalReportedCostUsd = 0.0f;
		ShellState.TotalSettlementDeltaUsd = 0.0f;
		ShellState.HighestSettlementDeltaUsd = 0.0f;
		ShellState.LatestExceptionEntryId.Reset();
		ShellState.bExceptionSummaryReady = false;
		ShellState.bExternalPortalHandoffReady = false;
		ShellState.bSettlementExceptionReviewReady = false;

		const FHyperTwistSpeechProviderBillingSettlementShellState& SettlementState =
			SessionState.ProviderBillingSettlementShellState;
		if (!SettlementState.IsStructurallyValid() || SettlementState.SettlementEntries.Num() <= 0)
		{
			FHyperTwistSpeechProviderSettlementExceptionIssue Issue;
			Issue.IssueId = TEXT("provider-settlement-exception-settlement-missing");
			Issue.IssueKind = TEXT("no-settlement-review");
			Issue.StatusLine = TEXT("Provider settlement exceptions are waiting for settlement review.");
			Issue.DetailLine = TEXT("Refresh the retained provider billing-settlement shell before settlement-exception posture begins.");
			Issue.RecommendedActionId = Profile.RefreshActionId;
			Issue.bRequiresOperatorAttention = false;
			AddSpeechProviderSettlementExceptionIssue(ShellState, Issue);
			ShellState.StatusLine = Issue.StatusLine;
			ShellState.DetailLine = Issue.DetailLine;
			ShellState.ActiveIssueCount = ShellState.Issues.Num();
			return;
		}

		const int32 ExceptionLimit = FMath::Max(1, Profile.RetainedExceptionEntryLimit);
		const int32 StartIndex =
			FMath::Max(0, SettlementState.SettlementEntries.Num() - ExceptionLimit);
		for (int32 EntryIndex = StartIndex;
			EntryIndex < SettlementState.SettlementEntries.Num();
			++EntryIndex)
		{
			const FHyperTwistSpeechProviderBillingSettlementEntry& SettlementEntry =
				SettlementState.SettlementEntries[EntryIndex];
			if (!SettlementEntry.IsStructurallyValid())
			{
				continue;
			}

			const bool bHasException =
				SettlementEntry.SourceKind.Contains(TEXT("fallback"), ESearchCase::IgnoreCase)
				|| !SettlementEntry.bHasProviderPostedCharge
				|| SettlementEntry.bRequiresManualReview
				|| SettlementEntry.bSettlementBlocked;
			if (!bHasException)
			{
				continue;
			}

			const FHyperTwistSpeechProviderSettlementExceptionEntry Entry =
				BuildSpeechProviderSettlementExceptionEntry(
					SettlementEntry,
					ShellState.SelectedSettlementWindowId
				);
			ShellState.ExceptionEntries.Add(Entry);
			ShellState.LatestExceptionEntryId = Entry.ExceptionEntryId;
			ShellState.LatestSourceKind = Entry.SourceKind;
			ShellState.TotalEstimatedCostUsd += Entry.EstimatedCostUsd;
			ShellState.TotalReportedCostUsd += Entry.ReportedCostUsd;
			ShellState.TotalSettlementDeltaUsd += Entry.SettlementDeltaUsd;
			ShellState.HighestSettlementDeltaUsd =
				FMath::Max(ShellState.HighestSettlementDeltaUsd, Entry.SettlementDeltaUsd);
			if (Entry.bExternalPortalHandoffReady)
			{
				++ShellState.ExternalPortalHandoffReadyEntryCount;
			}
			if (Entry.ExceptionKindId.Equals(TEXT("provider-charge-pending"), ESearchCase::IgnoreCase))
			{
				++ShellState.PendingChargeEntryCount;
			}
			if (Entry.bRequiresManualReview)
			{
				++ShellState.ManualReviewEntryCount;
			}
			if (Entry.ExceptionKindId.Equals(TEXT("route-degraded"), ESearchCase::IgnoreCase))
			{
				++ShellState.RouteDegradedEntryCount;
			}
			if (Entry.bSettlementBlocked)
			{
				++ShellState.BlockedSettlementEntryCount;
			}
		}

		ShellState.ExceptionEntryCount = ShellState.ExceptionEntries.Num();
		ShellState.bExceptionSummaryReady = ShellState.ExceptionEntryCount > 0;
		ShellState.bExternalPortalHandoffReady =
			Profile.bSupportsExternalPortalHandoff
			&& ShellState.ExternalPortalHandoffReadyEntryCount > 0;
		ShellState.bSettlementExceptionReviewReady =
			Profile.bSupportsSettlementExceptionReview
			&& ShellState.ExceptionEntryCount > 0;

		if (SettlementState.ActiveIssue.IsStructurallyValid()
			&& (SettlementState.ActiveIssue.IssueKind.Equals(TEXT("route-degraded"), ESearchCase::IgnoreCase)
				|| SettlementState.ActiveIssue.IssueKind.Equals(TEXT("hard-blocked"), ESearchCase::IgnoreCase)
				|| SettlementState.ActiveIssue.IssueKind.Equals(TEXT("rate-limited"), ESearchCase::IgnoreCase)
				|| SettlementState.ActiveIssue.IssueKind.Equals(TEXT("no-history"), ESearchCase::IgnoreCase)
				|| SettlementState.ActiveIssue.IssueKind.Equals(TEXT("no-receipt-review"), ESearchCase::IgnoreCase)))
		{
			FHyperTwistSpeechProviderSettlementExceptionIssue Issue;
			Issue.IssueId = FString::Printf(
				TEXT("provider-settlement-exception-%s"),
				*SettlementState.ActiveIssue.IssueKind
			);
			Issue.IssueKind = SettlementState.ActiveIssue.IssueKind;
			Issue.StatusLine = SettlementState.ActiveIssue.StatusLine;
			Issue.DetailLine = SettlementState.ActiveIssue.DetailLine;
			Issue.RecommendedActionId =
				SettlementState.ActiveIssue.IssueKind.Equals(TEXT("route-degraded"), ESearchCase::IgnoreCase)
				|| SettlementState.ActiveIssue.IssueKind.Equals(TEXT("hard-blocked"), ESearchCase::IgnoreCase)
				|| SettlementState.ActiveIssue.IssueKind.Equals(TEXT("rate-limited"), ESearchCase::IgnoreCase)
					? Profile.ExternalPortalHandoffActionId
					: Profile.RefreshActionId;
			Issue.bRequiresOperatorAttention =
				SettlementState.ActiveIssue.bRequiresOperatorAttention;
			AddSpeechProviderSettlementExceptionIssue(ShellState, Issue);
		}
		else if (ShellState.ManualReviewEntryCount > 0)
		{
			FHyperTwistSpeechProviderSettlementExceptionIssue Issue;
			Issue.IssueId = TEXT("provider-settlement-exception-external-handoff-review");
			Issue.IssueKind = TEXT("external-handoff-review-recommended");
			Issue.StatusLine =
				TEXT("Settlement exception review is ready for bounded external handoff.");
			Issue.DetailLine = TEXT("At least one retained provider charge still diverges from the first-party settlement expectation, so the next bounded step is reference-only external portal review rather than payment execution.");
			Issue.RecommendedActionId = Profile.ExternalPortalHandoffActionId;
			Issue.bRequiresOperatorAttention = true;
			AddSpeechProviderSettlementExceptionIssue(ShellState, Issue);
		}
		else if (ShellState.PendingChargeEntryCount > 0)
		{
			FHyperTwistSpeechProviderSettlementExceptionIssue Issue;
			Issue.IssueId = TEXT("provider-settlement-exception-charge-pending");
			Issue.IssueKind = TEXT("provider-charge-pending");
			Issue.StatusLine =
				TEXT("Provider settlement exceptions are waiting for posted charges.");
			Issue.DetailLine = TEXT("Settlement-exception posture is bounded and ready, but the retained settlement entries still show estimate-only provider cost posture rather than a posted charge.");
			Issue.RecommendedActionId = Profile.ExceptionInspectActionId;
			Issue.bRequiresOperatorAttention = false;
			AddSpeechProviderSettlementExceptionIssue(ShellState, Issue);
		}

		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.StatusLine = ShellState.ActiveIssue.StatusLine;
			ShellState.DetailLine = ShellState.ActiveIssue.DetailLine;
		}
		else if (ShellState.ExternalPortalHandoffReadyEntryCount > 0)
		{
			ShellState.StatusLine =
				TEXT("Provider settlement exceptions are ready for bounded external handoff review.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d retained settlement exceptions for %s are ready for reference-only provider portal review without widening into payment execution."),
				ShellState.ExternalPortalHandoffReadyEntryCount,
				*ShellState.ActiveProviderDisplayLabel
			);
		}
		else
		{
			ShellState.StatusLine =
				TEXT("Provider settlement exceptions remain bounded above reconciliation.");
			ShellState.DetailLine = FString::Printf(
				TEXT("%d retained settlement exceptions are available for %s, but external handoff is not ready yet."),
				ShellState.ExceptionEntryCount,
				*ShellState.ActiveProviderDisplayLabel
			);
		}

		ShellState.ExceptionSummaryText = FString::Printf(
			TEXT("providerProfileId=%s\nserviceLaneId=%s\nexceptionEntryCount=%d\n")
			TEXT("externalPortalHandoffReadyEntryCount=%d\npendingChargeEntryCount=%d\n")
			TEXT("manualReviewEntryCount=%d\nrouteDegradedEntryCount=%d\n")
			TEXT("blockedSettlementEntryCount=%d\ntotalEstimatedCostUsd=%.2f\n")
			TEXT("totalReportedCostUsd=%.2f\ntotalSettlementDeltaUsd=%.2f\n")
			TEXT("highestSettlementDeltaUsd=%.2f\nlatestExceptionEntryId=%s\n")
			TEXT("latestSourceKind=%s\nlastError=%s"),
			*ShellState.ActiveProviderProfileId,
			*ShellState.ActiveServiceLaneId,
			ShellState.ExceptionEntryCount,
			ShellState.ExternalPortalHandoffReadyEntryCount,
			ShellState.PendingChargeEntryCount,
			ShellState.ManualReviewEntryCount,
			ShellState.RouteDegradedEntryCount,
			ShellState.BlockedSettlementEntryCount,
			ShellState.TotalEstimatedCostUsd,
			ShellState.TotalReportedCostUsd,
			ShellState.TotalSettlementDeltaUsd,
			ShellState.HighestSettlementDeltaUsd,
			*ShellState.LatestExceptionEntryId,
			*ShellState.LatestSourceKind,
			*SessionState.LastError
		);
		ShellState.ActiveIssueCount = ShellState.Issues.Num();
	}

	void SynchronizeSpeechProviderSettlementExceptionState(
		FHyperTwistTrainingCompanionSpeechSessionState& SessionState
	)
	{
		FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
		ApplySpeechUsageCostDefaults(EffectiveConfig);
		if (!SessionState.ProviderBillingSettlementShellState.IsStructurallyValid())
		{
			SessionState.ProviderBillingSettlementShellState =
				BuildSpeechProviderBillingSettlementShellState(EffectiveConfig, &SessionState);
		}

		const FHyperTwistSpeechProviderSettlementExceptionShellProfile Profile =
			EffectiveConfig.ProviderSettlementExceptionShellProfileDefinition.IsStructurallyValid()
				? EffectiveConfig.ProviderSettlementExceptionShellProfileDefinition
				: BuildDefaultSpeechProviderSettlementExceptionShellProfile(
					!EffectiveConfig.ProviderSettlementExceptionShellProfileId.IsEmpty()
						? EffectiveConfig.ProviderSettlementExceptionShellProfileId
						: TEXT("speech-provider-settlement-exception-shell-v1")
				);

		if (!SessionState.ProviderSettlementExceptionShellState.IsStructurallyValid())
		{
			SessionState.ProviderSettlementExceptionShellState =
				BuildSpeechProviderSettlementExceptionShellState(EffectiveConfig, &SessionState);
		}

		FHyperTwistSpeechProviderSettlementExceptionShellState& ShellState =
			SessionState.ProviderSettlementExceptionShellState;
		ShellState.SettlementExceptionShellProfileId =
			Profile.SettlementExceptionShellProfileId;
		ShellState.AvailableActionIds.Reset();
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		ApplySpeechProviderSettlementExceptionPosture(Profile, SessionState, ShellState);

		ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ExceptionInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.ExternalPortalHandoffActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
		ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
		if (ShellState.ActiveIssue.IsStructurallyValid())
		{
			ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
		}
	}

	FHyperTwistSpeechMicrophoneShellState BuildCoachCommandMicrophoneShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState,
		const bool bSessionOpen
	)
	{
		const FHyperTwistSpeechMicrophoneShellProfile Profile =
			SessionConfig.MicrophoneShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.MicrophoneShellProfileDefinition
				: BuildDefaultCoachCommandMicrophoneShellProfile(
					!SessionConfig.MicrophoneShellProfileId.IsEmpty()
						? SessionConfig.MicrophoneShellProfileId
						: TEXT("coach-command-microphone-shell-v1")
				);

		FHyperTwistSpeechMicrophoneShellState ShellState;
		ShellState.MicrophoneShellProfileId = Profile.MicrophoneShellProfileId;
		ShellState.CaptureMode = Profile.CaptureMode;
		ShellState.ListeningContractId = !SessionConfig.ListeningContractId.IsEmpty()
			? SessionConfig.ListeningContractId
			: TEXT("listening-threshold-lifecycle");
		ShellState.InputRouteId = !SessionConfig.InputRouteId.IsEmpty()
			? SessionConfig.InputRouteId
			: TEXT("queue/listening");
		ShellState.LastLanguageCode =
			SessionConfig.LanguageMode.IsEmpty()
			|| SessionConfig.LanguageMode.Equals(TEXT("auto"), ESearchCase::IgnoreCase)
				? TEXT("en")
				: SessionConfig.LanguageMode;
		ShellState.PermissionStateId = TEXT("permission-granted");
		ShellState.CaptureRouteStateId = bSessionOpen ? TEXT("route-ready") : TEXT("route-closed");
		ShellState.StatusLine = bSessionOpen
			? TEXT("Microphone route ready for coach commands.")
			: TEXT("Microphone session closed.");
		ShellState.DetailLine = bSessionOpen
			? TEXT("Live capture is armed for the next bounded coach command.")
			: TEXT("Reopen the companion speech session when microphone capture is needed again.");
		ShellState.StepWindowMs = Profile.StepWindowMs;
		ShellState.CaptureWindowMs = Profile.CaptureWindowMs;
		ShellState.KeepWindowMs = Profile.KeepWindowMs;
		ShellState.VadThreshold = Profile.VadThreshold;
		ShellState.bSessionOpen = bSessionOpen;
		ShellState.bMicrophonePermissionGranted = true;
		ShellState.bCaptureRouteReady = true;
		ShellState.bCaptureActive = bSessionOpen;
		ShellState.bVadArmed = SessionConfig.bEnableVad;
		ShellState.bAwaitingSpeech = bSessionOpen;
		ShellState.bTranscriptionInFlight = false;
		ShellState.bCommitReady = false;
		ShellState.bPermissionPromptVisible = false;

		for (const FHyperTwistSpeechShellPanelLayout& Panel : Profile.Panels)
		{
			if (Panel.PanelId == TEXT("microphone-status-readout"))
			{
				ShellState.bStatusPanelVisible = Panel.bVisibleByDefault;
			}
			else if (Panel.PanelId == TEXT("vad-meter"))
			{
				ShellState.bVadMeterVisible = Panel.bVisibleByDefault;
			}
			else if (Panel.PanelId == TEXT("transcript-preview"))
			{
				ShellState.bTranscriptPreviewVisible = Panel.bVisibleByDefault;
			}
			else if (Panel.PanelId == TEXT("command-hints"))
			{
				ShellState.bCommandHintsVisible = Panel.bVisibleByDefault;
			}
		}

		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.Add(ActionBinding.ActionId);
		}

		if (PriorState != nullptr)
		{
			ShellState.SubmittedUtteranceCount = FMath::Max(0, PriorState->SubmittedUtteranceCount);
			ShellState.FinalTranscriptCount = FMath::Max(0, PriorState->FinalTranscriptCount);
			ShellState.bCommitReady =
				PriorState->bHasTranscriptResult && PriorState->LastTranscriptResult.IsStructurallyValid();
			ShellState.LastCommittedUtteranceId =
				!PriorState->LastTranscriptResult.UtteranceId.IsEmpty()
					? PriorState->LastTranscriptResult.UtteranceId
					: FString();
			ShellState.LastTranscriptPreview = PriorState->LastTranscriptResult.TranscriptText;
			if (!PriorState->LastTranscriptResult.LanguageCode.IsEmpty())
			{
				ShellState.LastLanguageCode = PriorState->LastTranscriptResult.LanguageCode;
			}

			if (PriorState->MicrophoneShellState.IsStructurallyValid())
			{
				ShellState.DetectedSpeechStartMs = PriorState->MicrophoneShellState.DetectedSpeechStartMs;
				ShellState.DetectedSpeechEndMs = PriorState->MicrophoneShellState.DetectedSpeechEndMs;
				ShellState.LastSilenceGapMs = PriorState->MicrophoneShellState.LastSilenceGapMs;
			}
		}

		return ShellState;
	}

	FHyperTwistSpeechDevicePermissionWorkflowState BuildSpeechDevicePermissionWorkflowState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechDevicePermissionWorkflowProfile Profile =
			SessionConfig.DevicePermissionWorkflowProfileDefinition.IsStructurallyValid()
				? SessionConfig.DevicePermissionWorkflowProfileDefinition
				: BuildDefaultSpeechDevicePermissionWorkflowProfile(
					!SessionConfig.DevicePermissionWorkflowProfileId.IsEmpty()
						? SessionConfig.DevicePermissionWorkflowProfileId
						: TEXT("speech-device-permission-workflow-v1")
				);

		FHyperTwistSpeechDevicePermissionWorkflowState WorkflowState;
		WorkflowState.DevicePermissionWorkflowProfileId =
			Profile.DevicePermissionWorkflowProfileId;
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			WorkflowState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->DevicePermissionWorkflowState.IsStructurallyValid()
			&& PriorState->DevicePermissionWorkflowState.DevicePermissionWorkflowProfileId
				== Profile.DevicePermissionWorkflowProfileId)
		{
			WorkflowState = PriorState->DevicePermissionWorkflowState;
			WorkflowState.DevicePermissionWorkflowProfileId =
				Profile.DevicePermissionWorkflowProfileId;
			WorkflowState.AvailableActionIds.Reset();
			for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
			{
				WorkflowState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
			}
		}

		return WorkflowState;
	}

	FHyperTwistSpeechNativeCaptureRouteWorkflowState BuildSpeechNativeCaptureRouteWorkflowState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechNativeCaptureRouteWorkflowProfile Profile =
			SessionConfig.NativeCaptureRouteWorkflowProfileDefinition.IsStructurallyValid()
				? SessionConfig.NativeCaptureRouteWorkflowProfileDefinition
				: BuildDefaultSpeechNativeCaptureRouteWorkflowProfile(
					!SessionConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty()
						? SessionConfig.NativeCaptureRouteWorkflowProfileId
						: TEXT("speech-native-capture-route-workflow-v1")
				);

		FHyperTwistSpeechNativeCaptureRouteWorkflowState WorkflowState;
		WorkflowState.NativeCaptureRouteWorkflowProfileId =
			Profile.NativeCaptureRouteWorkflowProfileId;
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			WorkflowState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->NativeCaptureRouteWorkflowState.IsStructurallyValid()
			&& PriorState->NativeCaptureRouteWorkflowState.NativeCaptureRouteWorkflowProfileId
				== Profile.NativeCaptureRouteWorkflowProfileId)
		{
			WorkflowState = PriorState->NativeCaptureRouteWorkflowState;
			WorkflowState.NativeCaptureRouteWorkflowProfileId =
				Profile.NativeCaptureRouteWorkflowProfileId;
			WorkflowState.AvailableActionIds.Reset();
			for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
			{
				WorkflowState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
			}
		}

		return WorkflowState;
	}

	FHyperTwistSpeechNativeCaptureRouteShellState BuildSpeechNativeCaptureRouteShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechNativeCaptureRouteShellProfile Profile =
			SessionConfig.NativeCaptureRouteShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.NativeCaptureRouteShellProfileDefinition
				: BuildDefaultSpeechNativeCaptureRouteShellProfile(
					!SessionConfig.NativeCaptureRouteShellProfileId.IsEmpty()
						? SessionConfig.NativeCaptureRouteShellProfileId
						: TEXT("speech-native-capture-route-shell-v1")
				);

		FHyperTwistSpeechNativeCaptureRouteShellState ShellState;
		ShellState.NativeCaptureRouteShellProfileId = Profile.NativeCaptureRouteShellProfileId;
		ShellState.NativeCaptureRouteWorkflowProfileId =
			!SessionConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty()
				? SessionConfig.NativeCaptureRouteWorkflowProfileId
				: TEXT("speech-native-capture-route-workflow-v1");
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->NativeCaptureRouteShellState.IsStructurallyValid()
			&& PriorState->NativeCaptureRouteShellState.NativeCaptureRouteShellProfileId
				== Profile.NativeCaptureRouteShellProfileId)
		{
			ShellState = PriorState->NativeCaptureRouteShellState;
			ShellState.NativeCaptureRouteShellProfileId =
				Profile.NativeCaptureRouteShellProfileId;
			ShellState.AvailableActionIds.Reset();
			for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
			{
				ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
			}
		}

		return ShellState;
	}

	FHyperTwistSpeechExternalDictationShellState BuildSpeechExternalDictationShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechExternalDictationShellProfile Profile =
			SessionConfig.ExternalDictationShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.ExternalDictationShellProfileDefinition
				: BuildDefaultSpeechExternalDictationShellProfile(
					!SessionConfig.ExternalDictationShellProfileId.IsEmpty()
						? SessionConfig.ExternalDictationShellProfileId
						: TEXT("speech-external-dictation-shell-v1")
				);

		FHyperTwistSpeechExternalDictationShellState ShellState;
		ShellState.ExternalDictationShellProfileId = Profile.ExternalDictationShellProfileId;
		ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.ProviderProfileId
			: TEXT("speech-provider/local-http-sidecar-profile-v1");
		ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
			? SessionConfig.OrchestrationProfile.ServiceLaneId
			: TEXT("speech/python-service");
		ShellState.TranscriptHistorySurfaceModeId = Profile.TranscriptHistorySurfaceMode;
		ShellState.OutputRoutingSurfaceModeId = Profile.OutputRoutingSurfaceMode;
		ShellState.PostProcessOverlaySurfaceModeId = Profile.PostProcessOverlaySurfaceMode;
		ShellState.GlobalHotkeySurfaceModeId = Profile.GlobalHotkeySurfaceMode;
		ShellState.InputDeviceSurfaceModeId = Profile.InputDeviceSurfaceMode;
		ShellState.OutputDeviceSurfaceModeId = Profile.OutputDeviceSurfaceMode;
		ShellState.MuteSurfaceModeId = Profile.MuteSurfaceMode;
		ShellState.MicrophoneModeSurfaceModeId = Profile.MicrophoneModeSurfaceMode;
		ShellState.LocalModelCatalogSurfaceModeId = Profile.LocalModelCatalogSurfaceMode;
		ShellState.ModelIntegritySurfaceModeId = Profile.ModelIntegritySurfaceMode;
		ShellState.ModelUnloadSurfaceModeId = Profile.ModelUnloadSurfaceMode;
		ShellState.OutputRouteOptions = BuildDefaultSpeechExternalDictationOutputRouteOptions();
		for (const FHyperTwistSpeechExternalDictationOutputRouteOption& OutputRoute :
			ShellState.OutputRouteOptions)
		{
			if (OutputRoute.bDefaultSelected)
			{
				ShellState.SelectedOutputRouteId = OutputRoute.OutputRouteId;
				break;
			}
		}
		if (ShellState.SelectedOutputRouteId.IsEmpty() && ShellState.OutputRouteOptions.Num() > 0)
		{
			ShellState.SelectedOutputRouteId = ShellState.OutputRouteOptions[0].OutputRouteId;
		}
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->ExternalDictationShellState.IsStructurallyValid()
			&& PriorState->ExternalDictationShellState.ExternalDictationShellProfileId
				== Profile.ExternalDictationShellProfileId)
		{
			ShellState = PriorState->ExternalDictationShellState;
			ShellState.ExternalDictationShellProfileId =
				Profile.ExternalDictationShellProfileId;
			ShellState.TranscriptHistorySurfaceModeId = Profile.TranscriptHistorySurfaceMode;
			ShellState.OutputRoutingSurfaceModeId = Profile.OutputRoutingSurfaceMode;
			ShellState.PostProcessOverlaySurfaceModeId = Profile.PostProcessOverlaySurfaceMode;
			ShellState.GlobalHotkeySurfaceModeId = Profile.GlobalHotkeySurfaceMode;
			ShellState.InputDeviceSurfaceModeId = Profile.InputDeviceSurfaceMode;
			ShellState.OutputDeviceSurfaceModeId = Profile.OutputDeviceSurfaceMode;
			ShellState.MuteSurfaceModeId = Profile.MuteSurfaceMode;
			ShellState.MicrophoneModeSurfaceModeId = Profile.MicrophoneModeSurfaceMode;
			ShellState.LocalModelCatalogSurfaceModeId = Profile.LocalModelCatalogSurfaceMode;
			ShellState.ModelIntegritySurfaceModeId = Profile.ModelIntegritySurfaceMode;
			ShellState.ModelUnloadSurfaceModeId = Profile.ModelUnloadSurfaceMode;
			if (ShellState.OutputRouteOptions.Num() <= 0)
			{
				ShellState.OutputRouteOptions =
					BuildDefaultSpeechExternalDictationOutputRouteOptions();
			}
			ShellState.AvailableActionIds.Reset();
			for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
			{
				ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
			}
		}

		ApplySpeechExternalDictationModelCatalogPosture(
			SessionConfig,
			FHyperTwistSpeechServiceHealth(),
			ShellState
		);

		return ShellState;
	}

	FHyperTwistSpeechUsageCostDashboardShellState BuildSpeechUsageCostDashboardShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechUsageCostDashboardShellProfile Profile =
			SessionConfig.UsageCostDashboardShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.UsageCostDashboardShellProfileDefinition
				: BuildDefaultSpeechUsageCostDashboardShellProfile(
					!SessionConfig.UsageCostDashboardShellProfileId.IsEmpty()
						? SessionConfig.UsageCostDashboardShellProfileId
						: TEXT("speech-provider-usage-cost-dashboard-shell-v1")
				);

		FHyperTwistSpeechUsageCostDashboardShellState ShellState;
		ShellState.DashboardShellProfileId = Profile.DashboardShellProfileId;
		ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.ProviderProfileId
			: TEXT("speech-provider/local-http-sidecar-profile-v1");
		ShellState.ActiveProviderDisplayLabel = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.DisplayLabel
			: TEXT("Local HTTP Speech Sidecar");
		ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
			? SessionConfig.OrchestrationProfile.ServiceLaneId
			: TEXT("speech/python-service");
		ShellState.ActiveRouteStateId = SessionConfig.ProviderRouteDecision.IsStructurallyValid()
			? SessionConfig.ProviderRouteDecision.RouteStateId
			: TEXT("route-ready");
		ShellState.UsageAggregationWindowId = SessionConfig.UsageEventTemplate.AggregationWindowId;
		ShellState.CostAggregationWindowId = SessionConfig.CostEventTemplate.AggregationWindowId;
		ShellState.UsageMeterKind = SessionConfig.UsageEventTemplate.MeterKind;
		ShellState.CurrencyCode = SessionConfig.CostEventTemplate.CurrencyCode;
		ShellState.LatestUsageEventId = SessionConfig.UsageEventTemplate.UsageEventId;
		ShellState.LatestCostEventId = SessionConfig.CostEventTemplate.CostEventId;
		ShellState.LatestQuotaStateId = TEXT("speech-quota-state/uninitialized");
		ShellState.LatestRouteDecisionId = SessionConfig.ProviderRouteDecision.IsStructurallyValid()
			? SessionConfig.ProviderRouteDecision.RouteDecisionId
			: TEXT("speech-route-decision/uninitialized");
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr && PriorState->UsageCostDashboardShellState.IsStructurallyValid())
		{
			ShellState = PriorState->UsageCostDashboardShellState;
			ShellState.DashboardShellProfileId = Profile.DashboardShellProfileId;
		}

		return ShellState;
	}

	FHyperTwistSpeechUsageCostHistoryExportShellState BuildSpeechUsageCostHistoryExportShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile =
			SessionConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.UsageCostHistoryExportShellProfileDefinition
				: BuildDefaultSpeechUsageCostHistoryExportShellProfile(
					!SessionConfig.UsageCostHistoryExportShellProfileId.IsEmpty()
						? SessionConfig.UsageCostHistoryExportShellProfileId
						: TEXT("speech-provider-usage-cost-history-export-shell-v1")
				);

		FHyperTwistSpeechUsageCostHistoryExportShellState ShellState;
		ShellState.HistoryExportShellProfileId = Profile.HistoryExportShellProfileId;
		ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.ProviderProfileId
			: TEXT("speech-provider/local-http-sidecar-profile-v1");
		ShellState.ActiveProviderDisplayLabel = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.DisplayLabel
			: TEXT("Local HTTP Speech Sidecar");
		ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
			? SessionConfig.OrchestrationProfile.ServiceLaneId
			: TEXT("speech/python-service");
		ShellState.SelectedHistoryWindowId = !SessionConfig.UsageEventTemplate.AggregationWindowId.IsEmpty()
			? SessionConfig.UsageEventTemplate.AggregationWindowId
			: TEXT("current-session");
		ShellState.ExportPreviewFormatId = Profile.ExportSurfaceMode;
		ShellState.bHistoryVisible = Profile.bSupportsHistoryTimeline;
		ShellState.bExportPreviewVisible = Profile.bSupportsExportPreview;
		ShellState.bEstimateWatermarkVisible = Profile.bSupportsEstimateWatermark;
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->UsageCostHistoryExportShellState.HistoryExportShellProfileId
				== Profile.HistoryExportShellProfileId)
		{
			ShellState = PriorState->UsageCostHistoryExportShellState;
			ShellState.HistoryExportShellProfileId = Profile.HistoryExportShellProfileId;
			ShellState.ExportPreviewFormatId = Profile.ExportSurfaceMode;
		}

		return ShellState;
	}

	FHyperTwistSpeechProviderReceiptReviewShellState BuildSpeechProviderReceiptReviewShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechProviderReceiptReviewShellProfile Profile =
			SessionConfig.ProviderReceiptReviewShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderReceiptReviewShellProfileDefinition
				: BuildDefaultSpeechProviderReceiptReviewShellProfile(
					!SessionConfig.ProviderReceiptReviewShellProfileId.IsEmpty()
						? SessionConfig.ProviderReceiptReviewShellProfileId
						: TEXT("speech-provider-receipt-review-shell-v1")
				);

		FHyperTwistSpeechProviderReceiptReviewShellState ShellState;
		ShellState.ReceiptReviewShellProfileId = Profile.ReceiptReviewShellProfileId;
		ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.ProviderProfileId
			: TEXT("speech-provider/local-http-sidecar-profile-v1");
		ShellState.ActiveProviderDisplayLabel = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.DisplayLabel
			: TEXT("Local HTTP Speech Sidecar");
		ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
			? SessionConfig.OrchestrationProfile.ServiceLaneId
			: TEXT("speech/python-service");
		ShellState.SelectedChargeWindowId = !SessionConfig.CostEventTemplate.AggregationWindowId.IsEmpty()
			? SessionConfig.CostEventTemplate.AggregationWindowId
			: TEXT("current-session");
		ShellState.PostedChargeInspectionModeId = Profile.ReceiptSurfaceMode;
		ShellState.bReceiptTimelineVisible = Profile.bSupportsReceiptTimeline;
		ShellState.bPostedChargeSummaryVisible = Profile.bSupportsPostedChargeInspection;
		ShellState.bVarianceReviewVisible = Profile.bSupportsVarianceReview;
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->ProviderReceiptReviewShellState.ReceiptReviewShellProfileId
				== Profile.ReceiptReviewShellProfileId)
		{
			ShellState = PriorState->ProviderReceiptReviewShellState;
			ShellState.ReceiptReviewShellProfileId = Profile.ReceiptReviewShellProfileId;
			ShellState.PostedChargeInspectionModeId = Profile.ReceiptSurfaceMode;
		}

		return ShellState;
	}

	FHyperTwistSpeechProviderBillingSettlementShellState BuildSpeechProviderBillingSettlementShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechProviderBillingSettlementShellProfile Profile =
			SessionConfig.ProviderBillingSettlementShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderBillingSettlementShellProfileDefinition
				: BuildDefaultSpeechProviderBillingSettlementShellProfile(
					!SessionConfig.ProviderBillingSettlementShellProfileId.IsEmpty()
						? SessionConfig.ProviderBillingSettlementShellProfileId
						: TEXT("speech-provider-billing-settlement-shell-v1")
				);

		FHyperTwistSpeechProviderBillingSettlementShellState ShellState;
		ShellState.BillingSettlementShellProfileId = Profile.BillingSettlementShellProfileId;
		ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.ProviderProfileId
			: TEXT("speech-provider/local-http-sidecar-profile-v1");
		ShellState.ActiveProviderDisplayLabel = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
			? SessionConfig.ProviderProfileDefinition.DisplayLabel
			: TEXT("Local HTTP Speech Sidecar");
		ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
			? SessionConfig.OrchestrationProfile.ServiceLaneId
			: TEXT("speech/python-service");
		ShellState.SelectedSettlementWindowId = !SessionConfig.CostEventTemplate.AggregationWindowId.IsEmpty()
			? SessionConfig.CostEventTemplate.AggregationWindowId
			: TEXT("current-session");
		ShellState.SettlementSurfaceModeId = Profile.SettlementSurfaceMode;
		ShellState.InvoiceReconciliationModeId = Profile.InvoiceReconciliationMode;
		ShellState.bSettlementTimelineVisible = Profile.bSupportsSettlementTimeline;
		ShellState.bInvoiceReconciliationVisible = Profile.bSupportsInvoiceReconciliation;
		ShellState.bSettlementReadinessVisible = Profile.bSupportsSettlementReadinessReview;
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->ProviderBillingSettlementShellState.BillingSettlementShellProfileId
				== Profile.BillingSettlementShellProfileId)
		{
			ShellState = PriorState->ProviderBillingSettlementShellState;
			ShellState.BillingSettlementShellProfileId = Profile.BillingSettlementShellProfileId;
			ShellState.SettlementSurfaceModeId = Profile.SettlementSurfaceMode;
			ShellState.InvoiceReconciliationModeId = Profile.InvoiceReconciliationMode;
		}

		return ShellState;
	}

	FHyperTwistSpeechProviderSettlementExceptionShellState
	BuildSpeechProviderSettlementExceptionShellState(
		const FHyperTwistSpeechSessionConfig& SessionConfig,
		const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
	)
	{
		const FHyperTwistSpeechProviderSettlementExceptionShellProfile Profile =
			SessionConfig.ProviderSettlementExceptionShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderSettlementExceptionShellProfileDefinition
				: BuildDefaultSpeechProviderSettlementExceptionShellProfile(
					!SessionConfig.ProviderSettlementExceptionShellProfileId.IsEmpty()
						? SessionConfig.ProviderSettlementExceptionShellProfileId
						: TEXT("speech-provider-settlement-exception-shell-v1")
				);

		FHyperTwistSpeechProviderSettlementExceptionShellState ShellState;
		ShellState.SettlementExceptionShellProfileId =
			Profile.SettlementExceptionShellProfileId;
		ShellState.ActiveProviderProfileId =
			SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderProfileDefinition.ProviderProfileId
				: TEXT("speech-provider/local-http-sidecar-profile-v1");
		ShellState.ActiveProviderDisplayLabel =
			SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
				? SessionConfig.ProviderProfileDefinition.DisplayLabel
				: TEXT("Local HTTP Speech Sidecar");
		ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
			? SessionConfig.OrchestrationProfile.ServiceLaneId
			: TEXT("speech/python-service");
		ShellState.SelectedSettlementWindowId = !SessionConfig.CostEventTemplate.AggregationWindowId.IsEmpty()
			? SessionConfig.CostEventTemplate.AggregationWindowId
			: TEXT("current-session");
		ShellState.ExceptionSurfaceModeId = Profile.ExceptionSurfaceMode;
		ShellState.ExternalPortalHandoffModeId = Profile.ExternalPortalHandoffMode;
		ShellState.bExceptionTimelineVisible = Profile.bSupportsExceptionTimeline;
		ShellState.bExternalPortalHandoffVisible = Profile.bSupportsExternalPortalHandoff;
		ShellState.bExceptionReviewVisible = Profile.bSupportsSettlementExceptionReview;
		for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
		{
			ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
		}

		if (PriorState != nullptr
			&& PriorState->ProviderSettlementExceptionShellState
				.SettlementExceptionShellProfileId
				== Profile.SettlementExceptionShellProfileId)
		{
			ShellState = PriorState->ProviderSettlementExceptionShellState;
			ShellState.SettlementExceptionShellProfileId =
				Profile.SettlementExceptionShellProfileId;
			ShellState.ExceptionSurfaceModeId = Profile.ExceptionSurfaceMode;
			ShellState.ExternalPortalHandoffModeId = Profile.ExternalPortalHandoffMode;
		}

		return ShellState;
	}

	FHyperTwistVisionCorrectionState BuildClassicCubeCorrectionState(
		const FHyperTwistVisionSessionConfig& SessionConfig,
		const FHyperTwistVisionReconstructionSession& ReconstructionSession,
		const FHyperTwistVisionFaceObservation& ObservedFace,
		const TArray<FString>& Warnings,
		const TArray<FHyperTwistVisionCorrectionResolution>& ResolutionLedger
	)
	{
		static constexpr float LowConfidenceThreshold = 0.85f;

		FHyperTwistVisionCorrectionState CorrectionState;
		const FHyperTwistVisionCorrectionProfile CorrectionProfile =
			SessionConfig.CorrectionProfileDefinition.IsStructurallyValid()
				? SessionConfig.CorrectionProfileDefinition
				: BuildDefaultClassicCubeCorrectionProfile(
					!SessionConfig.CorrectionProfileId.IsEmpty()
						? SessionConfig.CorrectionProfileId
						: TEXT("classic-cube-correction-shell-v1")
				);

		CorrectionState.CorrectionProfileId = CorrectionProfile.CorrectionProfileId;
		CorrectionState.MissingFaceCount = ReconstructionSession.IsStructurallyValid()
			? ReconstructionSession.MissingFaces.Num()
			: 6;
		CorrectionState.ResolutionLedger = ResolutionLedger;
		CorrectionState.ResolvedCorrectionCount = ResolutionLedger.Num();
		if (ResolutionLedger.Num() > 0)
		{
			CorrectionState.LastResolution = ResolutionLedger.Last();
		}
		CorrectionState.bManualCubeEditVisible =
			CorrectionProfile.bSupportsManualCubeEdit && ReconstructionSession.bHasCompleteClassicCubeNet;
		CorrectionState.bStageRestartVisible =
			CorrectionProfile.bSupportsStageRestart && Warnings.Num() > 0;

		TArray<FHyperTwistVisionCorrectionTarget> PendingTargets;
		TArray<FHyperTwistVisionCorrectionContradiction> Contradictions;
		if (ReconstructionSession.IsStructurallyValid())
		{
			for (const FHyperTwistVisionCommittedFaceState& FaceState : ReconstructionSession.CommittedFaces)
			{
				const FString FaceId = NormalizeRecognitionFaceId(FaceState.FaceId);
				const bool bHasCompleteNet = ReconstructionSession.bHasCompleteClassicCubeNet;
				if (HasAppliedResolutionForFace(ResolutionLedger, FaceState))
				{
					continue;
				}

				if (FaceState.bHasConflicts)
				{
					FHyperTwistVisionCorrectionContradiction Contradiction;
					Contradiction.ContradictionId = FString::Printf(TEXT("conflict-%s"), *FaceId);
					Contradiction.FaceId = FaceId;
					Contradiction.ContradictionKind = TEXT("conflicting-face");
					Contradiction.ObservationId = FaceState.LatestObservationId;
					Contradiction.RevisionCount = FaceState.RevisionCount;
					Contradiction.StatusLine =
						FString::Printf(TEXT("Face %s has conflicting sticker votes."), *FaceId);
					Contradiction.DetailLine =
						TEXT("At least one sticker vote disagrees with the current winner. Re-scan the face or review the manual cube edit before solve guidance continues.");
					Contradiction.bBlocksSolveExplanation = true;
					Contradiction.bManualReviewPreferred = bHasCompleteNet;
					for (const FHyperTwistVisionReconstructionStickerVote& Vote : FaceState.StickerVotes)
					{
						if (Vote.bHadConflict)
						{
							Contradiction.AffectedStickerIndices.Add(Vote.GridIndex);
						}
					}
					Contradictions.Add(Contradiction);

					FHyperTwistVisionCorrectionTarget Target;
					Target.FaceId = FaceId;
					Target.ReasonId = TEXT("conflicting-face");
					Target.RecommendedActionId = bHasCompleteNet
						? TEXT("apply-manual-corrections")
						: TEXT("rescan-target-face");
					Target.StatusLine = bHasCompleteNet
						? FString::Printf(TEXT("Review face %s before solve guidance begins."), *FaceId)
						: FString::Printf(TEXT("Re-scan face %s before capture advances."), *FaceId);
					Target.DetailLine = bHasCompleteNet
						? TEXT("Conflicting sticker votes survived the bounded reconstruction pass. Use cube edit or a targeted re-scan to close the contradiction.")
						: TEXT("Conflicting sticker votes are present while capture is still open. Re-scan the face before committing the remaining sides.");
					Target.PriorityOrdinal = 0;
					Target.bManualReviewPreferred = bHasCompleteNet;
					UpsertCorrectionTarget(PendingTargets, Target);
				}

				if (FaceState.RevisionCount > 0)
				{
					FHyperTwistVisionCorrectionContradiction Contradiction;
					Contradiction.ContradictionId = FString::Printf(TEXT("revision-%s"), *FaceId);
					Contradiction.FaceId = FaceId;
					Contradiction.ContradictionKind = TEXT("manual-revision");
					Contradiction.ObservationId = FaceState.LatestObservationId;
					Contradiction.RevisionCount = FaceState.RevisionCount;
					Contradiction.StatusLine =
						FString::Printf(TEXT("Face %s was recommitted and needs review."), *FaceId);
					Contradiction.DetailLine = FString::Printf(
						TEXT("The latest bounded reconstruction includes %d revision(s) on face %s. Preserve the latest capture or review the cube edit before solve guidance continues."),
						FaceState.RevisionCount,
						*FaceId
					);
					Contradiction.bBlocksSolveExplanation = true;
					Contradiction.bManualReviewPreferred = bHasCompleteNet;
					Contradictions.Add(Contradiction);

					FHyperTwistVisionCorrectionTarget Target;
					Target.FaceId = FaceId;
					Target.ReasonId = TEXT("revised-face");
					Target.RecommendedActionId = bHasCompleteNet
						? TEXT("apply-manual-corrections")
						: TEXT("rescan-target-face");
					Target.StatusLine = bHasCompleteNet
						? FString::Printf(TEXT("Review the revised face %s before solve guidance begins."), *FaceId)
						: FString::Printf(TEXT("Re-scan revised face %s before capture advances."), *FaceId);
					Target.DetailLine = FString::Printf(
						TEXT("Face %s has already been recommitted %d time(s) in this bounded session."),
						*FaceId,
						FaceState.RevisionCount
					);
					Target.PriorityOrdinal = 1;
					Target.bManualReviewPreferred = bHasCompleteNet;
					UpsertCorrectionTarget(PendingTargets, Target);
				}

				const float FaceConfidence = CalculateCommittedFaceConfidence(FaceState);
				if (FaceConfidence > 0.0f && FaceConfidence < LowConfidenceThreshold)
				{
					FHyperTwistVisionCorrectionTarget Target;
					Target.FaceId = FaceId;
					Target.ReasonId = TEXT("low-confidence-face");
					Target.RecommendedActionId = bHasCompleteNet
						? TEXT("apply-manual-corrections")
						: TEXT("rescan-target-face");
					Target.StatusLine = bHasCompleteNet
						? FString::Printf(TEXT("Review low-confidence face %s before solve guidance begins."), *FaceId)
						: FString::Printf(TEXT("Re-scan low-confidence face %s before capture advances."), *FaceId);
					Target.DetailLine = FString::Printf(
						TEXT("Average sticker confidence %.2f on face %s is below the bounded correction threshold %.2f."),
						FaceConfidence,
						*FaceId,
						LowConfidenceThreshold
					);
					Target.PriorityOrdinal = 2;
					Target.bManualReviewPreferred = bHasCompleteNet;
					UpsertCorrectionTarget(PendingTargets, Target);
				}
			}

			for (const FString& MissingFaceId : ReconstructionSession.MissingFaces)
			{
				const FString FaceId = NormalizeRecognitionFaceId(MissingFaceId);
				FHyperTwistVisionCorrectionTarget Target;
				Target.FaceId = FaceId;
				Target.ReasonId = TEXT("missing-face");
				Target.RecommendedActionId = TEXT("capture-target-face");
				Target.StatusLine =
					FString::Printf(TEXT("Capture face %s to continue the bounded reconstruction pass."), *FaceId);
				Target.DetailLine = FString::Printf(
					TEXT("Commit the next missing face. %d face(s) still need capture before solve guidance unlocks."),
					ReconstructionSession.MissingFaces.Num()
				);
				Target.PriorityOrdinal = 3;
				Target.bManualReviewPreferred = false;
				UpsertCorrectionTarget(PendingTargets, Target);
			}
		}

		if (PendingTargets.Num() == 0)
		{
			const FString FallbackFaceId = !ObservedFace.FaceId.IsEmpty()
				? NormalizeRecognitionFaceId(ObservedFace.FaceId)
				: TEXT("F");

			if (Warnings.Num() > 0)
			{
				FHyperTwistVisionCorrectionTarget Target;
				Target.FaceId = FallbackFaceId;
				Target.ReasonId = TEXT("warning-restart");
				Target.RecommendedActionId = TEXT("restart-browser-session");
				Target.StatusLine = TEXT("Restart the capture stage before correction continues.");
				Target.DetailLine = FString::Printf(
					TEXT("The bounded correction shell reported: %s"),
					*FString::Join(Warnings, TEXT(" | "))
				);
				Target.PriorityOrdinal = 0;
				Target.bManualReviewPreferred = false;
				UpsertCorrectionTarget(PendingTargets, Target);
			}
			else if (!ReconstructionSession.IsStructurallyValid())
			{
				FHyperTwistVisionCorrectionTarget Target;
				Target.FaceId = FallbackFaceId;
				Target.ReasonId = TEXT("capture-bootstrap");
				Target.RecommendedActionId = TEXT("capture-target-face");
				Target.StatusLine =
					FString::Printf(TEXT("Capture face %s to start bounded correction routing."), *FallbackFaceId);
				Target.DetailLine =
					TEXT("No committed reconstruction session is available yet. Capture the first face before correction or solve guidance can advance.");
				Target.PriorityOrdinal = 3;
				Target.bManualReviewPreferred = false;
				UpsertCorrectionTarget(PendingTargets, Target);
			}
		}

		PendingTargets.Sort(
			[](const FHyperTwistVisionCorrectionTarget& Left, const FHyperTwistVisionCorrectionTarget& Right)
			{
				if (Left.PriorityOrdinal != Right.PriorityOrdinal)
				{
					return Left.PriorityOrdinal < Right.PriorityOrdinal;
				}

				return GetClassicRecognitionFaceOrderIndex(Left.FaceId)
					< GetClassicRecognitionFaceOrderIndex(Right.FaceId);
			}
		);
		Contradictions.Sort(
			[](const FHyperTwistVisionCorrectionContradiction& Left, const FHyperTwistVisionCorrectionContradiction& Right)
			{
				return GetClassicRecognitionFaceOrderIndex(Left.FaceId)
					< GetClassicRecognitionFaceOrderIndex(Right.FaceId);
			}
		);

		CorrectionState.PendingTargets = PendingTargets;
		CorrectionState.Contradictions = Contradictions;
		CorrectionState.ContradictionCount = Contradictions.Num();
		CorrectionState.bCorrectionRequired = PendingTargets.Num() > 0;
		CorrectionState.bManualReviewRequired = Contradictions.Num() > 0;
		CorrectionState.bCorrectionComplete =
			ReconstructionSession.bHasCompleteClassicCubeNet && !CorrectionState.bCorrectionRequired;
		CorrectionState.bSolveExplanationBlocked = !CorrectionState.bCorrectionComplete;

		if (CorrectionState.bCorrectionRequired)
		{
			CorrectionState.ActiveTarget = PendingTargets[0];
			CorrectionState.ActiveTargetFaceId = CorrectionState.ActiveTarget.FaceId;
			CorrectionState.RecommendationStatusLine = CorrectionState.ActiveTarget.StatusLine;
			CorrectionState.RecommendationDetailLine = CorrectionState.ActiveTarget.DetailLine;
			CorrectionState.NextRecommendedActionId = CorrectionState.ActiveTarget.RecommendedActionId;
			CorrectionState.bTargetedRescanVisible =
				CorrectionState.ActiveTarget.RecommendedActionId == TEXT("capture-target-face")
				|| CorrectionState.ActiveTarget.RecommendedActionId == TEXT("rescan-target-face");
			CorrectionState.bManualCubeEditVisible =
				CorrectionProfile.bSupportsManualCubeEdit
				&& (ReconstructionSession.bHasCompleteClassicCubeNet
					|| CorrectionState.ActiveTarget.RecommendedActionId == TEXT("apply-manual-corrections"));
			CorrectionState.bStageRestartVisible =
				CorrectionProfile.bSupportsStageRestart
				&& (Warnings.Num() > 0
					|| CorrectionState.ActiveTarget.RecommendedActionId == TEXT("restart-browser-session"));
			CorrectionState.bManualReviewRequired =
				CorrectionState.bManualReviewRequired || CorrectionState.ActiveTarget.bManualReviewPreferred;
			CorrectionState.RecommendedStageId =
				CorrectionState.ActiveTarget.RecommendedActionId == TEXT("apply-manual-corrections")
					? TEXT("cube-edit")
					: TEXT("video-stream");
		}
		else
		{
			CorrectionState.RecommendedStageId = TEXT("orient-centers");
			CorrectionState.RecommendationStatusLine =
				TEXT("Correction is clear; solve guidance can begin.");
			CorrectionState.RecommendationDetailLine =
				TEXT("No missing faces, contradictions, or low-confidence targets remain in the bounded correction shell.");
			CorrectionState.NextRecommendedActionId = TEXT("start-solve-explanation");
			CorrectionState.bTargetedRescanVisible = false;
			CorrectionState.bManualCubeEditVisible =
				CorrectionProfile.bSupportsManualCubeEdit && ReconstructionSession.bHasCompleteClassicCubeNet;
		}

		return CorrectionState;
	}

	FHyperTwistVisionSolveExplanationState BuildClassicCubeSolveExplanationState(
		const FHyperTwistVisionSessionConfig& SessionConfig,
		const FHyperTwistVisionReconstructionSession& ReconstructionSession,
		const FHyperTwistVisionCorrectionState& CorrectionState
	)
	{
		FHyperTwistVisionSolveExplanationState SolveExplanationState;
		const FHyperTwistVisionSolveExplanationProfile SolveExplanationProfile =
			SessionConfig.SolveExplanationProfileDefinition.IsStructurallyValid()
				? SessionConfig.SolveExplanationProfileDefinition
				: BuildDefaultClassicCubeSolveExplanationProfile(
					!SessionConfig.SolveExplanationProfileId.IsEmpty()
						? SessionConfig.SolveExplanationProfileId
						: TEXT("classic-cube-solve-explanation-v1")
				);
		const FString PreferredLocaleCode =
			SessionConfig.ShellProfileDefinition.IsStructurallyValid()
				? SessionConfig.ShellProfileDefinition.DefaultLocaleCode
				: SolveExplanationProfile.DefaultLocaleCode;
		const FHyperTwistVisionLocaleOption ActiveLocaleOption = ResolveVisionLocaleOption(
			SolveExplanationProfile.SupportedLocales,
			PreferredLocaleCode
		);

		SolveExplanationState.ExplanationProfileId = SolveExplanationProfile.ExplanationProfileId;
		SolveExplanationState.ActiveLocaleCode = ActiveLocaleOption.LocaleCode;
		SolveExplanationState.ActiveLocaleDisplayLabel = ActiveLocaleOption.DisplayLabel;
		SolveExplanationState.ActiveLocaleScriptDirectionId = ActiveLocaleOption.ScriptDirectionId;
		SolveExplanationState.ActiveLocaleTextFlowProfileId = ActiveLocaleOption.TextFlowProfileId;
		SolveExplanationState.ActiveLocalePresentationProfileId = ActiveLocaleOption.PresentationProfileId;
		SolveExplanationState.FontReviewProfileId = SolveExplanationProfile.FontReviewProfileId;
		SolveExplanationState.ActiveFontReviewDescriptorId = ActiveLocaleOption.FontReviewDescriptorId;
		SolveExplanationState.bActiveLocaleRequiresComplexTextShaping =
			ActiveLocaleOption.bRequiresComplexTextShaping;
		SolveExplanationState.bBundledFontAssetDeferred =
			ActiveLocaleOption.bBundledFontAssetDeferred;
		SolveExplanationState.LocaleGuidanceMode = SolveExplanationProfile.LocaleGuidanceMode;
		SolveExplanationState.StartingOrientationHint = SolveExplanationProfile.StartingOrientationHint;
		SolveExplanationState.TotalStepCount = SolveExplanationProfile.Steps.Num();
		SolveExplanationState.bPlaybackDeferred = !SolveExplanationProfile.bSupportsPlaybackStage;
		SolveExplanationState.bRequiresFullReconstruction = true;
		SolveExplanationState.bLocaleCycleVisible = SolveExplanationProfile.SupportedLocales.Num() > 1;
		SolveExplanationState.bStartingOrientationHintVisible =
			!SolveExplanationProfile.StartingOrientationHint.IsEmpty();

		if (ReconstructionSession.bHasCompleteClassicCubeNet
			&& CorrectionState.IsStructurallyValid()
			&& CorrectionState.bCorrectionComplete)
		{
			SolveExplanationState.RecommendedStageId =
				SolveExplanationProfile.Steps.Num() > 0
					? SolveExplanationProfile.Steps[0].StageId
					: TEXT("orient-centers");
			SolveExplanationState.RecommendationStatusLine =
				TEXT("Solve guidance is ready after cube-edit review.");
			SolveExplanationState.RecommendationDetailLine =
				TEXT("Review any manual corrections, then start the bounded stage ladder. Playback ownership stays deferred in this packet.");
			SolveExplanationState.CurrentStepOrdinal = -1;
			SolveExplanationState.bReadyForExplanation = true;
			SolveExplanationState.bStartExplanationVisible = true;
			SolveExplanationState.bNextStepVisible = false;
			SolveExplanationState.bPreviousStepVisible = false;
		}
		else if (ReconstructionSession.bHasCompleteClassicCubeNet
			&& CorrectionState.IsStructurallyValid()
			&& CorrectionState.bCorrectionRequired)
		{
			SolveExplanationState.RecommendedStageId = !CorrectionState.RecommendedStageId.IsEmpty()
				? CorrectionState.RecommendedStageId
				: TEXT("video-stream");
			SolveExplanationState.RecommendationStatusLine =
				TEXT("Solve guidance stays blocked until correction closes.");
			SolveExplanationState.RecommendationDetailLine =
				!CorrectionState.RecommendationDetailLine.IsEmpty()
					? CorrectionState.RecommendationDetailLine
					: TEXT("Finish the bounded correction shell before solve guidance unlocks.");
			SolveExplanationState.CurrentStepOrdinal = -1;
			SolveExplanationState.bReadyForExplanation = false;
			SolveExplanationState.bStartExplanationVisible = false;
			SolveExplanationState.bNextStepVisible = false;
			SolveExplanationState.bPreviousStepVisible = false;
		}
		else
		{
			const int32 RemainingFaceCount = ReconstructionSession.IsStructurallyValid()
				? ReconstructionSession.MissingFaces.Num()
				: 6;
			SolveExplanationState.RecommendedStageId = TEXT("capture-remaining-faces");
			SolveExplanationState.RecommendationStatusLine =
				TEXT("Solve guidance unlocks after capture completes.");
			SolveExplanationState.RecommendationDetailLine = FString::Printf(
				TEXT("Commit the remaining %d face(s) and finish the bounded reconstruction pass before solve guidance unlocks."),
				RemainingFaceCount
			);
			SolveExplanationState.CurrentStepOrdinal = -1;
			SolveExplanationState.bReadyForExplanation = false;
			SolveExplanationState.bStartExplanationVisible = false;
			SolveExplanationState.bNextStepVisible = false;
			SolveExplanationState.bPreviousStepVisible = false;
		}

		return SolveExplanationState;
	}

	EHyperTwistPuzzleFamily ResolvePuzzleFamilyFromPuzzleId(const FString& PuzzleId)
	{
		FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
		if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
			PuzzleId,
			RetainedHyperDefinition
		))
		{
			return RetainedHyperDefinition.PuzzleFamily;
		}

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

	FString ResolveNotationProfileFromPuzzleId(const FString& PuzzleId)
	{
		FHyperTwistPuzzleDefinitionRef RetainedHyperDefinition;
		if (UHyperTwistTrainingCatalogLibrary::TryResolveRetainedHyperPuzzleDefinition(
			PuzzleId,
			RetainedHyperDefinition
		))
		{
			return RetainedHyperDefinition.NotationProfile;
		}

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

	int32 GetPenaltyOffsetMs(const EHyperTwistTrainingPenalty Penalty)
	{
		switch (Penalty)
		{
		case EHyperTwistTrainingPenalty::Plus2:
			return 2000;
		default:
			return 0;
		}
	}

	FString BuildSmartDeviceSessionId(
		const FString& TrainingSessionId,
		const FHyperTwistTrainingSmartDeviceIdentity& DeviceIdentity
	)
	{
		return FString::Printf(
			TEXT("smart-device-session/%s/%s/%s"),
			*TrainingSessionId,
			*DeviceIdentity.ProviderId,
			*DeviceIdentity.DeviceId
		);
	}

	FString BuildSmartDeviceAttemptId(
		const FString& TrainingSessionId,
		const FString& EventId
	)
	{
		return FString::Printf(TEXT("smart-device-attempt/%s/%s"), *TrainingSessionId, *EventId);
	}
}

	void UHyperTwistTrainingSubsystem::SetActiveAlgJsSequence(const FHyperTwistAlgorithmSequence& Sequence)
	{
		ActiveAlgJsSequence = Sequence;
		bHasActiveAlgJsSequence = true;
	}

	bool UHyperTwistTrainingSubsystem::TryGetActiveAlgJsSequence(FHyperTwistAlgorithmSequence& OutSequence) const
	{
		if (!bHasActiveAlgJsSequence)
		{
			OutSequence = FHyperTwistAlgorithmSequence();
			return false;
		}

		OutSequence = ActiveAlgJsSequence;
		return true;
	}

	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::HasActiveSmartDeviceSession() const
	{
		return bHasActiveSmartDeviceSession && ActiveSmartDeviceSessionRecord.IsStructurallyValid()
			&& ActiveSmartDeviceSessionRecord.IsOpen();
	}

	FHyperTwistTrainingSmartDeviceSessionRecord
	UHyperTwistTrainingSubsystem::GetActiveSmartDeviceSessionRecord() const
	{
		return ActiveSmartDeviceSessionRecord;
	}

	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 | Resolved %d | Finalizations %d"),
		*RecognitionProviderLabel,
		*RecognitionTransportState,
		ActiveRecognitionSessionState.bSessionOpen ? TEXT("open") : TEXT("closed"),
		ActiveRecognitionSessionState.SubmittedFrameCount,
		ActiveRecognitionSessionState.CommittedObservationCount,
		ActiveRecognitionSessionState.CorrectionEventCount,
		ActiveRecognitionSessionState.ResolvedCorrectionCount,
		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;
}

FHyperTwistTrainingPublicationBundle UHyperTwistTrainingSubsystem::GetActivePublicationBundle() const
{
	return ActivePublicationBundle;
}

FHyperTwistTrainingSocialChallengeBundle UHyperTwistTrainingSubsystem::GetActiveSocialChallengeBundle() const
{
	return ActiveSocialChallengeBundle;
}

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

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

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

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

FHyperTwistTrainingCompanionSpeechSessionState UHyperTwistTrainingSubsystem::GetActiveCompanionSpeechSessionState() const
{
	return ActiveCompanionSpeechSessionState;
}

#if WITH_AUTOMATION_TESTS
void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealthForAutomation()
{
	RefreshCompanionSpeechServiceHealth();
}
#endif

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

TArray<FHyperTwistTrainingFriendLinkRecord> UHyperTwistTrainingSubsystem::GetFriendLinksForUser(
	const FString& UserId
) const
{
	return UHyperTwistTrainingRepositoryLibrary::ListFriendLinksForUser(TrainingRepositoryState, UserId);
}

TArray<FHyperTwistTrainingNotificationRecord> UHyperTwistTrainingSubsystem::GetNotificationsForUser(
	const FString& UserId
) const
{
	return UHyperTwistTrainingRepositoryLibrary::ListNotificationsForUser(
		TrainingRepositoryState,
		UserId
	);
}

TArray<FHyperTwistTrainingChallengeRecord> UHyperTwistTrainingSubsystem::GetChallengesForUser(
	const FString& UserId
) const
{
	return UHyperTwistTrainingRepositoryLibrary::ListChallengesForUser(TrainingRepositoryState, UserId);
}

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::TryGetStoredFriendLinkRecord(
	const FString& UserId,
	const FString& FriendUserId,
	FHyperTwistTrainingFriendLinkRecord& OutFriendLinkRecord
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetFriendLinkRecord(
		TrainingRepositoryState,
		UserId,
		FriendUserId,
		OutFriendLinkRecord
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredNotificationRecord(
	const FString& NotificationId,
	FHyperTwistTrainingNotificationRecord& OutNotificationRecord
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetNotificationRecord(
		TrainingRepositoryState,
		NotificationId,
		OutNotificationRecord
	);
}

bool UHyperTwistTrainingSubsystem::TryGetStoredChallengeRecord(
	const FString& ChallengeId,
	FHyperTwistTrainingChallengeRecord& OutChallengeRecord
) const
{
	return UHyperTwistTrainingRepositoryLibrary::TryGetChallengeRecord(
		TrainingRepositoryState,
		ChallengeId,
		OutChallengeRecord
	);
}

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::SaveFriendLinkRecord(
	const FHyperTwistTrainingFriendLinkRecord& FriendLinkRecord
)
{
	if (!FriendLinkRecord.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertFriendLinkRecord(
		TrainingRepositoryState,
		FriendLinkRecord
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::SaveNotificationRecord(
	const FHyperTwistTrainingNotificationRecord& NotificationRecord
)
{
	if (!NotificationRecord.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertNotificationRecord(
		TrainingRepositoryState,
		NotificationRecord
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::MarkNotificationRead(const FString& NotificationId)
{
	if (NotificationId.IsEmpty())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::MarkNotificationRead(
		TrainingRepositoryState,
		NotificationId,
		FDateTime::UtcNow().ToIso8601()
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::AcknowledgeNotification(const FString& NotificationId)
{
	if (NotificationId.IsEmpty())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::AcknowledgeNotification(
		TrainingRepositoryState,
		NotificationId,
		FDateTime::UtcNow().ToIso8601()
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::ArchiveNotification(const FString& NotificationId)
{
	if (NotificationId.IsEmpty())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::ArchiveNotification(
		TrainingRepositoryState,
		NotificationId,
		FDateTime::UtcNow().ToIso8601()
	);
	RefreshRepositoryViews();
	return true;
}

bool UHyperTwistTrainingSubsystem::SaveChallengeRecord(
	const FHyperTwistTrainingChallengeRecord& ChallengeRecord
)
{
	if (!ChallengeRecord.IsStructurallyValid())
	{
		return false;
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertChallengeRecord(
		TrainingRepositoryState,
		ChallengeRecord
	);
	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 (HasActiveSmartDeviceSession())
	{
		StopActiveSmartDeviceSession(TEXT("replaced-by-new-training-run"));
	}
	if (ActiveRecognitionSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveRecognitionSession(CloseError);
	}
	if (ActiveCompanionSpeechSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveCompanionSpeechSession(CloseError);
	}
	ResetRecognitionSessionState();
	ResetCompanionSpeechSessionState();
	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::StartActiveLiveTimerForCurrentDrillCase()
{
	if (!HasActiveMethodDrillRun()
		|| !HasActiveRun()
		|| !ActiveMethodDrillRunState.CurrentCase.IsStructurallyValid()
		|| !ActiveRunState.Session.IsStructurallyValid()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid()
		|| ActiveMethodDrillRunState.CurrentCase.CaseId != ActiveRunState.CurrentSelection.TrainingCase.CaseId)
	{
		return false;
	}

	return StartActiveLiveTimer();
}

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

FHyperTwistTrainingDrillTimerCompletionResult UHyperTwistTrainingSubsystem::SubmitAndAdvanceActiveDrillTimerAttempt(
	const EHyperTwistTrainingAttemptResult Result
)
{
	FHyperTwistTrainingDrillTimerCompletionResult CompletionResult;
	if (!HasActiveMethodDrillRun()
		|| !HasActiveRun()
		|| !ActiveMethodDrillRunState.CurrentCase.IsStructurallyValid()
		|| !ActiveRunState.Session.IsStructurallyValid()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid()
		|| ActiveMethodDrillRunState.CurrentCase.CaseId != ActiveRunState.CurrentSelection.TrainingCase.CaseId)
	{
		return CompletionResult;
	}

	CompletionResult.SubmitStepResult = SubmitActiveLiveTimedAttempt(Result);
	CompletionResult.bSubmitSucceeded = CompletionResult.SubmitStepResult.IsStructurallyValid();
	if (CompletionResult.bSubmitSucceeded)
	{
		CompletionResult.UpdatedDrillRunState = AdvanceActiveMethodDrillCase();
		CompletionResult.bAdvanceSucceeded = CompletionResult.UpdatedDrillRunState.IsStructurallyValid();
		OnDrillTimerCompleted.Broadcast(CompletionResult);
	}

	return CompletionResult;
}

FHyperTwistTrainingSmartDeviceSessionRecord UHyperTwistTrainingSubsystem::StartActiveSmartDeviceSession(
	const FHyperTwistTrainingSmartDeviceIdentity& DeviceIdentity,
	const FString& DeviceSessionId
)
{
	if (!CanUseSmartDeviceBridge()
		|| !ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
	{
		return FHyperTwistTrainingSmartDeviceSessionRecord();
	}

	const FHyperTwistTrainingSmartDeviceIdentity NormalizedDeviceIdentity =
		NormalizeSmartDeviceIdentity(DeviceIdentity);
	if (!NormalizedDeviceIdentity.IsStructurallyValid())
	{
		return FHyperTwistTrainingSmartDeviceSessionRecord();
	}

	const FString ResolvedDeviceSessionId = !DeviceSessionId.IsEmpty()
		? DeviceSessionId
		: HyperTwistTrainingSubsystemInternal::BuildSmartDeviceSessionId(
			ActiveRunState.Session.TrainingSessionId,
			NormalizedDeviceIdentity
		);
	if (ResolvedDeviceSessionId.IsEmpty())
	{
		return FHyperTwistTrainingSmartDeviceSessionRecord();
	}

	if (HasActiveSmartDeviceSession())
	{
		const bool bMatchesCurrentSession =
			ActiveSmartDeviceSessionRecord.DeviceSessionId == ResolvedDeviceSessionId
			|| (ActiveSmartDeviceSessionRecord.TrainingSessionId == ActiveRunState.Session.TrainingSessionId
				&& ActiveSmartDeviceSessionRecord.DeviceIdentity.ProviderId == NormalizedDeviceIdentity.ProviderId
				&& ActiveSmartDeviceSessionRecord.DeviceIdentity.DeviceId == NormalizedDeviceIdentity.DeviceId);
		if (bMatchesCurrentSession)
		{
			return ActiveSmartDeviceSessionRecord;
		}

		StopActiveSmartDeviceSession(TEXT("replaced-by-new-smart-device-session"));
	}

	const FString NowUtc = FDateTime::UtcNow().ToIso8601();
	ActiveSmartDeviceSessionRecord = FHyperTwistTrainingSmartDeviceSessionRecord();
	ActiveSmartDeviceSessionRecord.DeviceSessionId = ResolvedDeviceSessionId;
	ActiveSmartDeviceSessionRecord.TrainingSessionId = ActiveRunState.Session.TrainingSessionId;
	ActiveSmartDeviceSessionRecord.UserId = ActiveRunState.Session.UserId;
	ActiveSmartDeviceSessionRecord.DeckId = ActiveRunState.Session.DeckId;
	ActiveSmartDeviceSessionRecord.CaseId = ActiveRunState.CurrentSelection.TrainingCase.CaseId;
	ActiveSmartDeviceSessionRecord.DeviceIdentity = NormalizedDeviceIdentity;
	ActiveSmartDeviceSessionRecord.StartedAtUtc = NowUtc;
	ActiveSmartDeviceSessionRecord.LastUpdatedAtUtc = NowUtc;
	ActiveSmartDeviceSessionRecord.ConnectionState =
		EHyperTwistTrainingSmartDeviceConnectionState::Connected;
	ActiveSmartDeviceSessionRecord.LastStatusReason = TEXT("smart-device-session-started");
	bHasActiveSmartDeviceSession = ActiveSmartDeviceSessionRecord.IsStructurallyValid();
	if (bHasActiveSmartDeviceSession)
	{
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertSmartDeviceSessionRecord(
			TrainingRepositoryState,
			ActiveSmartDeviceSessionRecord
		);
		RefreshRepositoryViews();
	}

	return ActiveSmartDeviceSessionRecord;
}

FHyperTwistTrainingSmartDeviceSessionRecord UHyperTwistTrainingSubsystem::StopActiveSmartDeviceSession(
	const FString& CloseReason
)
{
	if (!ActiveSmartDeviceSessionRecord.IsStructurallyValid())
	{
		return FHyperTwistTrainingSmartDeviceSessionRecord();
	}

	const FString NowUtc = FDateTime::UtcNow().ToIso8601();
	const FString ResolvedReason = !CloseReason.IsEmpty()
		? CloseReason
		: TEXT("smart-device-session-stopped");
	ActiveSmartDeviceSessionRecord.LastUpdatedAtUtc = NowUtc;
	if (ActiveSmartDeviceSessionRecord.EndedAtUtc.IsEmpty())
	{
		ActiveSmartDeviceSessionRecord.EndedAtUtc = NowUtc;
	}
	if (ActiveSmartDeviceSessionRecord.ConnectionState
		!= EHyperTwistTrainingSmartDeviceConnectionState::Faulted
		&& ActiveSmartDeviceSessionRecord.ConnectionState
			!= EHyperTwistTrainingSmartDeviceConnectionState::Disconnected)
	{
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Closed;
	}
	ActiveSmartDeviceSessionRecord.LastStatusReason = ResolvedReason;
	bHasActiveSmartDeviceSession = false;
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertSmartDeviceSessionRecord(
		TrainingRepositoryState,
		ActiveSmartDeviceSessionRecord
	);
	RefreshRepositoryViews();
	return ActiveSmartDeviceSessionRecord;
}

FHyperTwistTrainingSmartDeviceIngestionResult UHyperTwistTrainingSubsystem::IngestSmartDeviceEventFrame(
	const FHyperTwistTrainingSmartDeviceEventFrame& EventFrame
)
{
	FHyperTwistTrainingSmartDeviceIngestionResult IngestionResult;
	IngestionResult.EventKind = EventFrame.EventKind;

	if (!CanUseSmartDeviceBridge() || !HasActiveSmartDeviceSession())
	{
		IngestionResult.FailureReason = TEXT("smart-device-session-unavailable");
		return IngestionResult;
	}

	FHyperTwistTrainingSmartDeviceEventFrame NormalizedEventFrame =
		NormalizeSmartDeviceEventFrame(EventFrame);
	IngestionResult.DeviceSessionId = NormalizedEventFrame.DeviceSessionId;
	IngestionResult.EventId = NormalizedEventFrame.EventId;
	IngestionResult.EventKey = NormalizedEventFrame.BuildEventKey();
	if (!NormalizedEventFrame.IsStructurallyValid()
		|| NormalizedEventFrame.DeviceSessionId != ActiveSmartDeviceSessionRecord.DeviceSessionId
		|| NormalizedEventFrame.TrainingSessionId != ActiveRunState.Session.TrainingSessionId)
	{
		IngestionResult.FailureReason = TEXT("smart-device-event-invalid");
		return IngestionResult;
	}

	if (UHyperTwistTrainingRepositoryLibrary::HasSmartDeviceEventFrame(
			TrainingRepositoryState,
			NormalizedEventFrame.DeviceSessionId,
			NormalizedEventFrame.EventId))
	{
		ActiveSmartDeviceSessionRecord.DuplicateEventCount += 1;
		ActiveSmartDeviceSessionRecord.LastUpdatedAtUtc = NormalizedEventFrame.OccurredAtUtc;
		ActiveSmartDeviceSessionRecord.LastEventId = NormalizedEventFrame.EventId;
		ActiveSmartDeviceSessionRecord.LastEventKey = NormalizedEventFrame.BuildEventKey();
		ActiveSmartDeviceSessionRecord.LastEventKind = NormalizedEventFrame.EventKind;
		ActiveSmartDeviceSessionRecord.LastStatusReason = TEXT("smart-device-event-duplicate");
		TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertSmartDeviceSessionRecord(
			TrainingRepositoryState,
			ActiveSmartDeviceSessionRecord
		);
		RefreshRepositoryViews();
		IngestionResult.bDuplicate = true;
		return IngestionResult;
	}

	switch (NormalizedEventFrame.EventKind)
	{
	case EHyperTwistTrainingSmartDeviceEventKind::Connected:
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Connected;
		break;
	case EHyperTwistTrainingSmartDeviceEventKind::InspectionStarted:
		if (!ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid() || !StartActiveLiveTimer())
		{
			IngestionResult.FailureReason = TEXT("smart-device-inspection-start-failed");
			return IngestionResult;
		}
		IngestionResult.bUpdatedTimerState = true;
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Streaming;
		break;
	case EHyperTwistTrainingSmartDeviceEventKind::SolveStarted:
		if (!ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
		{
			IngestionResult.FailureReason = TEXT("smart-device-solve-start-failed");
			return IngestionResult;
		}
		if (!HasActiveLiveTimer() && !StartActiveLiveTimer())
		{
			IngestionResult.FailureReason = TEXT("smart-device-solve-start-failed");
			return IngestionResult;
		}
		RefreshActiveLiveTimerState();
		if (ActiveLiveTimerState.Phase == EHyperTwistTrainingLiveTimerPhase::Inspection
			&& !AdvanceActiveLiveTimerToSolvePhase())
		{
			IngestionResult.FailureReason = TEXT("smart-device-solve-phase-advance-failed");
			return IngestionResult;
		}
		IngestionResult.bUpdatedTimerState = true;
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Streaming;
		break;
	case EHyperTwistTrainingSmartDeviceEventKind::SplitCaptured:
		if (!HasActiveLiveTimer())
		{
			IngestionResult.FailureReason = TEXT("smart-device-split-without-live-timer");
			return IngestionResult;
		}
		MergeSmartDeviceSplitCapturesIntoLiveTimer(NormalizedEventFrame.SplitCaptures);
		IngestionResult.bUpdatedTimerState = true;
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Streaming;
		break;
	case EHyperTwistTrainingSmartDeviceEventKind::AttemptFinished:
	{
		const FHyperTwistTrainingAttempt Attempt =
			BuildSmartDeviceAttemptFromEventFrame(NormalizedEventFrame);
		if (!Attempt.IsStructurallyValid())
		{
			IngestionResult.FailureReason = TEXT("smart-device-attempt-payload-invalid");
			return IngestionResult;
		}

		const FHyperTwistTrainingRunStepResult StepResult =
			SubmitTrainingAttempt(Attempt, FMath::Max(Attempt.TotalTimeMs, 0));
		if (!StepResult.IsStructurallyValid())
		{
			IngestionResult.FailureReason = TEXT("smart-device-attempt-submit-failed");
			return IngestionResult;
		}

		NormalizedEventFrame.LinkedAttemptId = Attempt.AttemptId;
		IngestionResult.LinkedAttemptId = Attempt.AttemptId;
		IngestionResult.bSubmittedAttempt = true;
		if (HasActiveLiveTimer())
		{
			ResetActiveLiveTimerState();
		}
		if (ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
		{
			ActiveSmartDeviceSessionRecord.CaseId = ActiveRunState.CurrentSelection.TrainingCase.CaseId;
		}
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Streaming;
		break;
	}
	case EHyperTwistTrainingSmartDeviceEventKind::Disconnected:
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Disconnected;
		ActiveSmartDeviceSessionRecord.EndedAtUtc = NormalizedEventFrame.OccurredAtUtc;
		break;
	case EHyperTwistTrainingSmartDeviceEventKind::Faulted:
		ActiveSmartDeviceSessionRecord.ConnectionState =
			EHyperTwistTrainingSmartDeviceConnectionState::Faulted;
		ActiveSmartDeviceSessionRecord.EndedAtUtc = NormalizedEventFrame.OccurredAtUtc;
		break;
	case EHyperTwistTrainingSmartDeviceEventKind::None:
	default:
		IngestionResult.FailureReason = TEXT("smart-device-event-kind-unsupported");
		return IngestionResult;
	}

	ActiveSmartDeviceSessionRecord.LastUpdatedAtUtc = NormalizedEventFrame.OccurredAtUtc;
	ActiveSmartDeviceSessionRecord.LastSequenceNumber = FMath::Max(
		ActiveSmartDeviceSessionRecord.LastSequenceNumber,
		NormalizedEventFrame.SequenceNumber
	);
	ActiveSmartDeviceSessionRecord.LastEventId = NormalizedEventFrame.EventId;
	ActiveSmartDeviceSessionRecord.LastEventKey = NormalizedEventFrame.BuildEventKey();
	ActiveSmartDeviceSessionRecord.LastEventKind = NormalizedEventFrame.EventKind;
	ActiveSmartDeviceSessionRecord.LastStatusReason = !NormalizedEventFrame.StatusReason.IsEmpty()
		? NormalizedEventFrame.StatusReason
		: TEXT("smart-device-event-applied");
	const bool bShouldRetainAdvancedCaseId =
		NormalizedEventFrame.EventKind == EHyperTwistTrainingSmartDeviceEventKind::AttemptFinished
		&& ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid();
	if (!NormalizedEventFrame.CaseId.IsEmpty() && !bShouldRetainAdvancedCaseId)
	{
		ActiveSmartDeviceSessionRecord.CaseId = NormalizedEventFrame.CaseId;
	}
	if (!NormalizedEventFrame.LinkedAttemptId.IsEmpty())
	{
		ActiveSmartDeviceSessionRecord.LinkedAttemptIds.AddUnique(NormalizedEventFrame.LinkedAttemptId);
		ActiveSmartDeviceSessionRecord.LastLinkedAttemptId = NormalizedEventFrame.LinkedAttemptId;
		ActiveSmartDeviceSessionRecord.LinkedAttemptCount =
			ActiveSmartDeviceSessionRecord.LinkedAttemptIds.Num();
	}

	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertSmartDeviceSessionRecord(
		TrainingRepositoryState,
		ActiveSmartDeviceSessionRecord
	);
	TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordSmartDeviceEventFrame(
		TrainingRepositoryState,
		NormalizedEventFrame
	);
	RefreshRepositoryViews();

	if (NormalizedEventFrame.EventKind == EHyperTwistTrainingSmartDeviceEventKind::Disconnected
		|| NormalizedEventFrame.EventKind == EHyperTwistTrainingSmartDeviceEventKind::Faulted)
	{
		bHasActiveSmartDeviceSession = false;
	}

	IngestionResult.bAccepted = true;
	return IngestionResult;
}

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

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

	if (HasActiveSmartDeviceSession())
	{
		StopActiveSmartDeviceSession(
			bAbortSession ? TEXT("training-run-aborted") : TEXT("training-run-completed")
		);
	}
	if (ActiveRecognitionSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveRecognitionSession(CloseError);
	}
	if (ActiveCompanionSpeechSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveCompanionSpeechSession(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();
	ResetCompanionSpeechSessionState();
	RefreshRepositoryViews();
	return ActiveRunState.Session;
}

void UHyperTwistTrainingSubsystem::ClearActiveRun()
{
	if (ActiveRecognitionSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveRecognitionSession(CloseError);
	}
	if (ActiveCompanionSpeechSessionState.bSessionOpen)
	{
		FString CloseError;
		CloseActiveCompanionSpeechSession(CloseError);
	}
	if (HasActiveSmartDeviceSession())
	{
		StopActiveSmartDeviceSession(TEXT("training-run-cleared"));
	}
	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();
	ResetCompanionSpeechSessionState();
	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.ActiveReconstructionSession = FHyperTwistVisionReconstructionSession();
	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();
	}
	if (NormalizedFrame.ObservationProfile.IsEmpty()
		&& HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(ActiveRecognitionSessionState.SessionConfig))
	{
		NormalizedFrame.ObservationProfile = TEXT("classic-3x3-face-observation-v1");
	}

	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;
	}
	if (HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(ActiveRecognitionSessionState.SessionConfig))
	{
		Result.ShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeWebcamShellState(
			ActiveRecognitionSessionState.SessionConfig,
			ActiveRecognitionSessionState.ActiveReconstructionSession,
			!Result.ObservedFace.FaceId.IsEmpty() ? Result.ObservedFace.FaceId : NormalizedFrame.TargetFaceHint,
			FString()
		);
		Result.BrowserShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeBrowserShellState(
			ActiveRecognitionSessionState.SessionConfig,
			ActiveRecognitionSessionState.ActiveReconstructionSession,
			Result.ObservedFace
		);
	}

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

	const bool bIsQbrClassicRoute =
		HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(ActiveRecognitionSessionState.SessionConfig);
	if (bIsQbrClassicRoute
		&& HyperTwistTrainingSubsystemInternal::IsCorrectionResolutionCommitKind(NormalizedRequest.CommitKind))
	{
		Result.SessionId = NormalizedRequest.SessionId;
		Result.CommitKind = NormalizedRequest.CommitKind;
		Result.Snapshot.State.SourceSessionId = NormalizedRequest.SessionId;
		Result.ReconstructionSession = ActiveRecognitionSessionState.ActiveReconstructionSession;
		Result.MissingUnits = Result.ReconstructionSession.MissingFaces;
		Result.Confidence = Result.ReconstructionSession.ConfidenceRollup;

		const FHyperTwistVisionFaceObservation ReferenceObservation =
			ActiveRecognitionSessionState.LastCommitResult.ObservedFace.IsStructurallyValid()
				? ActiveRecognitionSessionState.LastCommitResult.ObservedFace
				: ActiveRecognitionSessionState.LastPreviewResult.ObservedFace;
		Result.CorrectionState =
			HyperTwistTrainingSubsystemInternal::BuildClassicCubeCorrectionState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				ReferenceObservation,
				Result.Warnings,
				ActiveRecognitionSessionState.CorrectionResolutionLedger
			);

		const FString RequestedFaceId = !NormalizedRequest.TargetFace.IsEmpty()
			? HyperTwistTrainingSubsystemInternal::NormalizeRecognitionFaceId(NormalizedRequest.TargetFace)
			: Result.CorrectionState.ActiveTargetFaceId;
		const FHyperTwistVisionCorrectionTarget* RequestedTarget =
			HyperTwistTrainingSubsystemInternal::FindCorrectionTarget(Result.CorrectionState, RequestedFaceId);
		const FHyperTwistVisionCommittedFaceState* RequestedFaceState =
			HyperTwistTrainingSubsystemInternal::FindCommittedFaceState(Result.ReconstructionSession, RequestedFaceId);
		bool bAppliedResolution = false;
		bool bAddedNewResolution = false;

		if (!Result.ReconstructionSession.IsStructurallyValid())
		{
			Result.Warnings.Add(TEXT("correction-resolution-unavailable"));
		}
		else if (!Result.ReconstructionSession.bHasCompleteClassicCubeNet)
		{
			Result.Warnings.Add(TEXT("correction-resolution-requires-complete-net"));
		}
		else if (RequestedFaceId.IsEmpty())
		{
			Result.Warnings.Add(TEXT("correction-target-face-required"));
		}
		else if (RequestedTarget == nullptr)
		{
			Result.Warnings.Add(TEXT("correction-target-unavailable"));
		}
		else if (RequestedTarget->RecommendedActionId != TEXT("apply-manual-corrections"))
		{
			Result.Warnings.Add(TEXT("correction-target-does-not-support-manual-resolution"));
		}
		else if (RequestedFaceState == nullptr)
		{
			Result.Warnings.Add(TEXT("correction-face-state-unavailable"));
		}
		else
		{
			Result.CommittedUnit = RequestedFaceId;
			Result.ObservedFace =
				HyperTwistTrainingSubsystemInternal::BuildObservationFromCommittedFaceState(*RequestedFaceState);

			FHyperTwistVisionCorrectionResolution AppliedResolution =
				HyperTwistTrainingSubsystemInternal::BuildCorrectionResolution(
					NormalizedRequest,
					Result.CorrectionState,
					*RequestedFaceState
				);
			HyperTwistTrainingSubsystemInternal::UpsertCorrectionResolution(
				ActiveRecognitionSessionState.CorrectionResolutionLedger,
				AppliedResolution,
				bAddedNewResolution
			);
			ActiveRecognitionSessionState.LastCorrectionResolution = AppliedResolution;
			if (bAddedNewResolution)
			{
				++ActiveRecognitionSessionState.ResolvedCorrectionCount;
			}

			FHyperTwistPuzzleState ReconstructedState;
			FHyperTwistStateSnapshot ReconstructedSnapshot;
			if (HyperTwistTrainingSubsystemInternal::TryBuildClassicRecognitionStateSnapshot(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				ReconstructedState,
				ReconstructedSnapshot
			))
			{
				Result.Snapshot = ReconstructedSnapshot;
			}
			else
			{
				Result.Snapshot = FHyperTwistStateSnapshot();
				Result.Warnings.AddUnique(TEXT("recognition-reconstruction-unavailable"));
			}

			Result.ShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeWebcamShellState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				RequestedFaceId,
				Result.CommittedUnit
			);
			Result.BrowserShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeBrowserShellState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				Result.ObservedFace
			);
			Result.CorrectionState =
				HyperTwistTrainingSubsystemInternal::BuildClassicCubeCorrectionState(
					ActiveRecognitionSessionState.SessionConfig,
					Result.ReconstructionSession,
					Result.ObservedFace,
					Result.Warnings,
					ActiveRecognitionSessionState.CorrectionResolutionLedger
				);
			AppliedResolution.bClearsSolveExplanationBlock = !Result.CorrectionState.bSolveExplanationBlocked;
			ActiveRecognitionSessionState.LastCorrectionResolution = AppliedResolution;
			HyperTwistTrainingSubsystemInternal::UpsertCorrectionResolution(
				ActiveRecognitionSessionState.CorrectionResolutionLedger,
				AppliedResolution,
				bAddedNewResolution
			);
			Result.AppliedCorrectionResolution = AppliedResolution;
			Result.CorrectionState.LastResolution = AppliedResolution;
			Result.SolveExplanationState =
				HyperTwistTrainingSubsystemInternal::BuildClassicCubeSolveExplanationState(
					ActiveRecognitionSessionState.SessionConfig,
					Result.ReconstructionSession,
					Result.CorrectionState
				);
			bAppliedResolution = true;
		}

		if (!Result.ObservedFace.IsStructurallyValid() && RequestedFaceState != nullptr)
		{
			Result.ObservedFace =
				HyperTwistTrainingSubsystemInternal::BuildObservationFromCommittedFaceState(*RequestedFaceState);
		}
		if (!Result.ShellState.IsStructurallyValid())
		{
			Result.ShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeWebcamShellState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				RequestedFaceId,
				Result.CommittedUnit
			);
		}
		if (!Result.BrowserShellState.IsStructurallyValid())
		{
			Result.BrowserShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeBrowserShellState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				Result.ObservedFace
			);
		}
		if (!Result.CorrectionState.IsStructurallyValid())
		{
			Result.CorrectionState =
				HyperTwistTrainingSubsystemInternal::BuildClassicCubeCorrectionState(
					ActiveRecognitionSessionState.SessionConfig,
					Result.ReconstructionSession,
					Result.ObservedFace,
					Result.Warnings,
					ActiveRecognitionSessionState.CorrectionResolutionLedger
				);
		}
		if (!Result.SolveExplanationState.IsStructurallyValid())
		{
			Result.SolveExplanationState =
				HyperTwistTrainingSubsystemInternal::BuildClassicCubeSolveExplanationState(
					ActiveRecognitionSessionState.SessionConfig,
					Result.ReconstructionSession,
					Result.CorrectionState
				);
		}

		if (bAppliedResolution)
		{
			FHyperTwistReplayRecognitionPayload CorrectionPayload;
			CorrectionPayload.Snapshot = Result.Snapshot;
			CorrectionPayload.Confidence = Result.Confidence;
			CorrectionPayload.CommittedFaceOrStage = !RequestedFaceId.IsEmpty()
				? RequestedFaceId
				: NormalizedRequest.CommitKind;
			AppendRecognitionReplayEvent(
				EHyperTwistReplayEventType::RecognitionCorrection,
				CorrectionPayload,
				INDEX_NONE
			);
			++ActiveRecognitionSessionState.CorrectionEventCount;
		}

		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 (bAppliedResolution)
		{
			SynchronizeRecognitionReplayMutation();
		}
		return Result;
	}

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

	bool bWasReconstructionRevision = false;
	if (HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(ActiveRecognitionSessionState.SessionConfig)
		&& Result.ObservedFace.IsStructurallyValid())
	{
		if (Result.CommittedUnit.IsEmpty())
		{
			Result.CommittedUnit = HyperTwistTrainingSubsystemInternal::NormalizeRecognitionFaceId(
				Result.ObservedFace.FaceId
			);
		}

		Result.ReconstructionSession =
			HyperTwistTrainingSubsystemInternal::BuildClassicRecognitionReconstructionSession(
				ActiveRecognitionSessionState.SessionConfig,
				Result.SessionId,
				ActiveRecognitionSessionState.ActiveReconstructionSession,
				Result.ObservedFace,
				bWasReconstructionRevision
			);
		ActiveRecognitionSessionState.ActiveReconstructionSession = Result.ReconstructionSession;

		TArray<FString> ProviderMissingUnits = Result.MissingUnits;
		Result.MissingUnits = Result.ReconstructionSession.MissingFaces;
		for (const FString& ProviderMissingUnit : ProviderMissingUnits)
		{
			Result.MissingUnits.AddUnique(ProviderMissingUnit);
		}

		Result.Confidence = Result.ReconstructionSession.ConfidenceRollup;
		if (Result.ReconstructionSession.bHasCompleteClassicCubeNet)
		{
			FHyperTwistPuzzleState ReconstructedState;
			FHyperTwistStateSnapshot ReconstructedSnapshot;
			if (HyperTwistTrainingSubsystemInternal::TryBuildClassicRecognitionStateSnapshot(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				ReconstructedState,
				ReconstructedSnapshot
			))
			{
				Result.Snapshot = ReconstructedSnapshot;
			}
			else
			{
				Result.Snapshot = FHyperTwistStateSnapshot();
			}
		}
		else
		{
			Result.Snapshot = FHyperTwistStateSnapshot();
		}
	}
	if (HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(ActiveRecognitionSessionState.SessionConfig))
	{
		Result.ShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeWebcamShellState(
			ActiveRecognitionSessionState.SessionConfig,
			Result.ReconstructionSession,
			Result.ObservedFace.FaceId,
			Result.CommittedUnit
		);
		Result.BrowserShellState = HyperTwistTrainingSubsystemInternal::BuildClassicCubeBrowserShellState(
			ActiveRecognitionSessionState.SessionConfig,
			Result.ReconstructionSession,
			Result.ObservedFace
		);
		Result.CorrectionState =
			HyperTwistTrainingSubsystemInternal::BuildClassicCubeCorrectionState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				Result.ObservedFace,
				Result.Warnings,
				ActiveRecognitionSessionState.CorrectionResolutionLedger
			);
		Result.SolveExplanationState =
			HyperTwistTrainingSubsystemInternal::BuildClassicCubeSolveExplanationState(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				Result.CorrectionState
			);
	}

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

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

	if (HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(ActiveRecognitionSessionState.SessionConfig))
	{
		Result.ReconstructionSession = ActiveRecognitionSessionState.ActiveReconstructionSession;
		if (Result.ReconstructionSession.IsStructurallyValid())
		{
			Result.ConfidenceRollup = Result.ReconstructionSession.ConfidenceRollup;
		}

		if (Result.ReconstructionSession.IsStructurallyValid()
			&& Result.ReconstructionSession.bHasCompleteClassicCubeNet)
		{
			FHyperTwistPuzzleState ReconstructedState;
			FHyperTwistStateSnapshot ReconstructedSnapshot;
			if (HyperTwistTrainingSubsystemInternal::TryBuildClassicRecognitionStateSnapshot(
				ActiveRecognitionSessionState.SessionConfig,
				Result.ReconstructionSession,
				ReconstructedState,
				ReconstructedSnapshot
			))
			{
				Result.FinalState = ReconstructedState;
				Result.FinalSnapshot = ReconstructedSnapshot;
			}
			else
			{
				Result.FinalState = FHyperTwistPuzzleState();
				Result.FinalSnapshot = FHyperTwistStateSnapshot();
				Result.NormalizationWarnings.AddUnique(TEXT("recognition-reconstruction-unavailable"));
			}
		}
		else
		{
			Result.FinalState = FHyperTwistPuzzleState();
			Result.FinalSnapshot = FHyperTwistStateSnapshot();
			Result.NormalizationWarnings.AddUnique(
				Result.ReconstructionSession.IsStructurallyValid()
					? TEXT("recognition-reconstruction-incomplete")
					: TEXT("recognition-reconstruction-unavailable")
			);
		}
	}

	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.ActiveReconstructionSession = FHyperTwistVisionReconstructionSession();
	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.ActiveReconstructionSession = FHyperTwistVisionReconstructionSession();
	ActiveRecognitionSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveRecognitionSessionState.LastError.Reset();
	RefreshRecognitionServiceHealth();
	return true;
}

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

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

	IHyperTwistSpeechClient* SpeechClient = HyperTwistTrainingSubsystemInternal::ResolveSpeechClient(
		ResolveCompanionSpeechClientObject()
	);
	if (SpeechClient == nullptr)
	{
		OutError = TEXT("speech-client-unavailable");
		ActiveCompanionSpeechSessionState.LastError = OutError;
		RefreshCompanionSpeechServiceHealth();
		return false;
	}

	const FHyperTwistSpeechSessionConfig SessionConfig = BuildActiveCompanionSpeechSessionConfig();
	ActiveCompanionSpeechSessionState.SessionConfig = SessionConfig;
	if (SessionConfig.SessionId.IsEmpty())
	{
		OutError = TEXT("speech-session-id-unavailable");
		ActiveCompanionSpeechSessionState.LastError = OutError;
		RefreshCompanionSpeechServiceHealth();
		return false;
	}

	if (ActiveCompanionSpeechSessionState.bSessionOpen
		&& ActiveCompanionSpeechSessionState.ActiveSessionId == SessionConfig.SessionId)
	{
		const FHyperTwistTrainingCompanionSpeechSessionState PriorSessionState =
			ActiveCompanionSpeechSessionState;
		ActiveCompanionSpeechSessionState.SessionConfig = SessionConfig;
		ActiveCompanionSpeechSessionState.MicrophoneShellState =
			HyperTwistTrainingSubsystemInternal::BuildCoachCommandMicrophoneShellState(
				SessionConfig,
				&PriorSessionState,
				true
			);
		ActiveCompanionSpeechSessionState.ExternalDictationShellState =
			HyperTwistTrainingSubsystemInternal::BuildSpeechExternalDictationShellState(
				SessionConfig,
				&PriorSessionState
			);
		ActiveCompanionSpeechSessionState.LastError.Reset();
		RefreshCompanionSpeechServiceHealth();
		return true;
	}

	ActiveCompanionSpeechSessionState.SubmittedUtteranceCount = 0;
	ActiveCompanionSpeechSessionState.FinalTranscriptCount = 0;
	ActiveCompanionSpeechSessionState.bHasTranscriptResult = false;
	ActiveCompanionSpeechSessionState.LastTranscriptResult = FHyperTwistSpeechTranscriptResult();
	ActiveCompanionSpeechSessionState.DevicePermissionWorkflowState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechDevicePermissionWorkflowState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.NativeCaptureRouteWorkflowState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechNativeCaptureRouteWorkflowState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.NativeCaptureRouteShellState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechNativeCaptureRouteShellState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.ExternalDictationShellState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechExternalDictationShellState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.UsageCostHistoryExportShellState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechUsageCostHistoryExportShellState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.ProviderReceiptReviewShellState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechProviderReceiptReviewShellState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.ProviderBillingSettlementShellState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechProviderBillingSettlementShellState(
			SessionConfig,
			nullptr
		);
	ActiveCompanionSpeechSessionState.ProviderSettlementExceptionShellState =
		HyperTwistTrainingSubsystemInternal::BuildSpeechProviderSettlementExceptionShellState(
			SessionConfig,
			nullptr
		);

	if (ActiveCompanionSpeechSessionState.bSessionOpen
		&& ActiveCompanionSpeechSessionState.ActiveSessionId != SessionConfig.SessionId)
	{
		FString CloseError;
		SpeechClient->CloseSpeechSession(ActiveCompanionSpeechSessionState.ActiveSessionId, CloseError);
	}

	if (!SpeechClient->OpenSpeechSession(SessionConfig, OutError))
	{
		ActiveCompanionSpeechSessionState.LastError = OutError;
		RefreshCompanionSpeechServiceHealth();
		return false;
	}

	const FString OpenedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveCompanionSpeechSessionState.bSessionOpen = true;
	ActiveCompanionSpeechSessionState.bUsingProviderBackedClient =
		ActiveCompanionSpeechClientObject != nullptr
		&& ActiveCompanionSpeechClientObject->IsA<UHyperTwistHttpSpeechClient>();
	ActiveCompanionSpeechSessionState.ActiveSessionId = SessionConfig.SessionId;
	ActiveCompanionSpeechSessionState.OpenedAtUtc = OpenedAtUtc;
	ActiveCompanionSpeechSessionState.LastUpdatedAtUtc = OpenedAtUtc;
	ActiveCompanionSpeechSessionState.LastError.Reset();
	ActiveCompanionSpeechSessionState.SessionConfig = SessionConfig;
	ActiveCompanionSpeechSessionState.bHasTranscriptResult = false;
	ActiveCompanionSpeechSessionState.LastTranscriptResult = FHyperTwistSpeechTranscriptResult();
	ActiveCompanionSpeechSessionState.MicrophoneShellState =
		HyperTwistTrainingSubsystemInternal::BuildCoachCommandMicrophoneShellState(
			SessionConfig,
			&ActiveCompanionSpeechSessionState,
			true
		);
	RefreshCompanionSpeechServiceHealth();
	return true;
}

FHyperTwistSpeechTranscriptResult UHyperTwistTrainingSubsystem::SubmitActiveCompanionSpeechUtterance(
	const FHyperTwistSpeechUtteranceEnvelope& Utterance
)
{
	FHyperTwistSpeechTranscriptResult Result;

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

	FString OpenError;
	if (!OpenActiveCompanionSpeechSession(OpenError))
	{
		Result.SessionId = !Utterance.SessionId.IsEmpty()
			? Utterance.SessionId
			: BuildActiveCompanionSpeechSessionConfig().SessionId;
		Result.UtteranceId = Utterance.UtteranceId;
		Result.Warnings.Add(OpenError.IsEmpty() ? TEXT("speech-session-open-failed") : OpenError);
		return Result;
	}

	IHyperTwistSpeechClient* SpeechClient = HyperTwistTrainingSubsystemInternal::ResolveSpeechClient(
		ResolveCompanionSpeechClientObject()
	);
	if (SpeechClient == nullptr)
	{
		Result.Warnings.Add(TEXT("speech-client-unavailable"));
		ActiveCompanionSpeechSessionState.LastError = Result.Warnings[0];
		ActiveCompanionSpeechSessionState.ServiceHealth.LastError = ActiveCompanionSpeechSessionState.LastError;
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechDevicePermissionWorkflowState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteWorkflowState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteShellState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechExternalDictationShellState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderReceiptReviewState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderBillingSettlementState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderSettlementExceptionState(
			ActiveCompanionSpeechSessionState
		);
		return Result;
	}

	FHyperTwistSpeechUtteranceEnvelope NormalizedUtterance = Utterance;
	NormalizedUtterance.SessionId = ActiveCompanionSpeechSessionState.ActiveSessionId;
	if (NormalizedUtterance.UtteranceId.IsEmpty())
	{
		NormalizedUtterance.UtteranceId = HyperTwistTrainingSubsystemInternal::BuildSpeechUtteranceId(
			NormalizedUtterance.SessionId,
			ActiveCompanionSpeechSessionState.SubmittedUtteranceCount + 1
		);
	}
	if (NormalizedUtterance.CapturedAtUtc.IsEmpty())
	{
		NormalizedUtterance.CapturedAtUtc = FDateTime::UtcNow().ToIso8601();
	}
	if (NormalizedUtterance.SampleRateHz <= 0)
	{
		NormalizedUtterance.SampleRateHz = ActiveCompanionSpeechSessionState.SessionConfig.SampleRateHz;
	}
	if (NormalizedUtterance.ChannelCount <= 0)
	{
		NormalizedUtterance.ChannelCount = ActiveCompanionSpeechSessionState.SessionConfig.ChannelCount;
	}
	if (NormalizedUtterance.LocalCommandHints.Num() <= 0)
	{
		NormalizedUtterance.LocalCommandHints = ActiveCompanionSpeechSessionState.SessionConfig.CommandHints;
	}
	NormalizedUtterance.SilenceGapMs = FMath::Max(0, NormalizedUtterance.SilenceGapMs);
	NormalizedUtterance.SpeechStartMs = FMath::Max(0, NormalizedUtterance.SpeechStartMs);
	NormalizedUtterance.SpeechEndMs = FMath::Max(
		NormalizedUtterance.SpeechStartMs,
		NormalizedUtterance.SpeechEndMs
	);
	if (!ActiveCompanionSpeechSessionState.MicrophoneShellState.IsStructurallyValid())
	{
		ActiveCompanionSpeechSessionState.MicrophoneShellState =
			HyperTwistTrainingSubsystemInternal::BuildCoachCommandMicrophoneShellState(
				ActiveCompanionSpeechSessionState.SessionConfig,
				&ActiveCompanionSpeechSessionState,
				true
			);
	}

	ActiveCompanionSpeechSessionState.MicrophoneShellState.ActiveUtteranceId = NormalizedUtterance.UtteranceId;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.DetectedSpeechStartMs =
		NormalizedUtterance.SpeechStartMs;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.DetectedSpeechEndMs =
		NormalizedUtterance.SpeechEndMs;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.LastSilenceGapMs =
		NormalizedUtterance.SilenceGapMs;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bSessionOpen = true;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bCaptureActive = false;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bVadArmed =
		ActiveCompanionSpeechSessionState.SessionConfig.bEnableVad;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bAwaitingSpeech = false;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bTranscriptionInFlight = true;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bCommitReady = false;

	Result = SpeechClient->TranscribeSpeechUtterance(NormalizedUtterance);
	if (Result.SessionId.IsEmpty())
	{
		Result.SessionId = NormalizedUtterance.SessionId;
	}
	if (Result.UtteranceId.IsEmpty())
	{
		Result.UtteranceId = NormalizedUtterance.UtteranceId;
	}
	if (Result.TaskKind.IsEmpty())
	{
		Result.TaskKind = ActiveCompanionSpeechSessionState.SessionConfig.TaskKind;
	}
	if (Result.GrammarProfileId.IsEmpty())
	{
		Result.GrammarProfileId = ActiveCompanionSpeechSessionState.SessionConfig.GrammarProfileId;
	}
	if (Result.OrchestrationProfileId.IsEmpty())
	{
		Result.OrchestrationProfileId =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.OrchestrationProfileId;
	}
	if (Result.ServiceLaneId.IsEmpty())
	{
		Result.ServiceLaneId =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.ServiceLaneId;
	}
	if (Result.RequestedBatchSize <= 0)
	{
		Result.RequestedBatchSize =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.PreferredBatchSize;
	}
	if (Result.ProcessedClipCount <= 0)
	{
		Result.ProcessedClipCount = 1;
	}
	if (Result.AppliedBatchCollectionWindowMs <= 0)
	{
		Result.AppliedBatchCollectionWindowMs =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile
				.BatchCollectionWindowMs;
	}
	Result.bUsedBatchedInference =
		Result.bUsedBatchedInference
		|| ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.bEnableBatchedInference;
	Result.bWordTimestampsRequested =
		Result.bWordTimestampsRequested
		|| ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.bEnableWordTimestamps;
	Result.bConditionedOnPreviousText =
		Result.bConditionedOnPreviousText
		|| ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.bConditionOnPreviousText;
	if (Result.AppliedPromptRoutingModeId.IsEmpty())
	{
		Result.AppliedPromptRoutingModeId =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile
				.PromptRoutingModeId;
	}
	if (Result.AppliedPrefixHint.IsEmpty())
	{
		Result.AppliedPrefixHint =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.PrefixHint;
	}
	if (Result.AppliedHotwordHints.Num() <= 0)
	{
		Result.AppliedHotwordHints =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile.HotwordHints;
	}
	if (Result.AppliedRetrievalContextLaneId.IsEmpty())
	{
		Result.AppliedRetrievalContextLaneId =
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile
				.RetrievalContextLaneId;
	}
	if (Result.AppliedRetrievedHints.Num() <= 0
		&& ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile
			.bEnableRetrievedHintAugmentation)
	{
		const int32 MaxRetrievedHintCount = FMath::Max(
			ActiveCompanionSpeechSessionState.SessionConfig.OrchestrationProfile
				.MaxRetrievedHintCount,
			0
		);
		for (const FString& CommandHint :
			ActiveCompanionSpeechSessionState.SessionConfig.CommandHints)
		{
			if (!CommandHint.IsEmpty())
			{
				Result.AppliedRetrievedHints.Add(CommandHint);
			}
			if (Result.AppliedRetrievedHints.Num() >= MaxRetrievedHintCount)
			{
				break;
			}
		}
	}
	Result.RetrievedHintCount = Result.AppliedRetrievedHints.Num();
	Result.bUsedRetrievedHintAugmentation =
		Result.bUsedRetrievedHintAugmentation || Result.RetrievedHintCount > 0;
	Result.bUsedPromptHints =
		Result.bUsedPromptHints
		|| !Result.AppliedPrefixHint.IsEmpty()
		|| Result.AppliedHotwordHints.Num() > 0
		|| Result.bUsedRetrievedHintAugmentation;
	if (Result.LanguageProbability <= 0.0f && !Result.LanguageCode.IsEmpty())
	{
		Result.LanguageProbability = Result.LanguageCode.Equals(TEXT("und"), ESearchCase::IgnoreCase) ? 0.0f : 0.95f;
	}
	if (Result.TranscriptText.IsEmpty() && Result.Segments.Num() > 0)
	{
		TArray<FString> SegmentTexts;
		for (const FHyperTwistSpeechTranscriptSegment& Segment : Result.Segments)
		{
			if (!Segment.Text.IsEmpty())
			{
				SegmentTexts.Add(Segment.Text);
			}
		}
		Result.TranscriptText = FString::Join(SegmentTexts, TEXT(" "));
	}

	++ActiveCompanionSpeechSessionState.SubmittedUtteranceCount;
	if (Result.bIsFinal && Result.IsStructurallyValid())
	{
		++ActiveCompanionSpeechSessionState.FinalTranscriptCount;
	}
	ActiveCompanionSpeechSessionState.bHasTranscriptResult = true;
	ActiveCompanionSpeechSessionState.LastTranscriptResult = Result;
	ActiveCompanionSpeechSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveCompanionSpeechSessionState.LastError =
		Result.Warnings.Num() > 0 ? FString::Join(Result.Warnings, TEXT(" | ")) : FString();
	ActiveCompanionSpeechSessionState.ServiceHealth.LastError = ActiveCompanionSpeechSessionState.LastError;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.ActiveUtteranceId.Reset();
	if (Result.bIsFinal && Result.IsStructurallyValid())
	{
		ActiveCompanionSpeechSessionState.MicrophoneShellState.LastCommittedUtteranceId = Result.UtteranceId;
	}
	ActiveCompanionSpeechSessionState.MicrophoneShellState.LastTranscriptPreview = Result.TranscriptText;
	if (!Result.LanguageCode.IsEmpty())
	{
		ActiveCompanionSpeechSessionState.MicrophoneShellState.LastLanguageCode = Result.LanguageCode;
	}
	ActiveCompanionSpeechSessionState.MicrophoneShellState.SubmittedUtteranceCount =
		ActiveCompanionSpeechSessionState.SubmittedUtteranceCount;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.FinalTranscriptCount =
		ActiveCompanionSpeechSessionState.FinalTranscriptCount;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bSessionOpen = true;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bCaptureActive = true;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bVadArmed =
		ActiveCompanionSpeechSessionState.SessionConfig.bEnableVad;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bAwaitingSpeech = true;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bTranscriptionInFlight = false;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bCommitReady =
		Result.bIsFinal && Result.IsStructurallyValid();
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechDevicePermissionWorkflowState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteWorkflowState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteShellState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechExternalDictationShellState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderReceiptReviewState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderBillingSettlementState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderSettlementExceptionState(
		ActiveCompanionSpeechSessionState
	);

	return Result;
}

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

	if (!ActiveCompanionSpeechSessionState.bSessionOpen || ActiveCompanionSpeechSessionState.ActiveSessionId.IsEmpty())
	{
		RefreshCompanionSpeechServiceHealth();
		return true;
	}

	IHyperTwistSpeechClient* SpeechClient = HyperTwistTrainingSubsystemInternal::ResolveSpeechClient(
		ResolveCompanionSpeechClientObject()
	);
	if (SpeechClient == nullptr)
	{
		OutError = TEXT("speech-client-unavailable");
		ActiveCompanionSpeechSessionState.LastError = OutError;
		RefreshCompanionSpeechServiceHealth();
		return false;
	}

	const FString SessionId = ActiveCompanionSpeechSessionState.ActiveSessionId;
	const bool bClosed = SpeechClient->CloseSpeechSession(SessionId, OutError);
	if (!bClosed && OutError != TEXT("session-not-open"))
	{
		ActiveCompanionSpeechSessionState.LastError = OutError;
		RefreshCompanionSpeechServiceHealth();
		return false;
	}

	ActiveCompanionSpeechSessionState.bSessionOpen = false;
	ActiveCompanionSpeechSessionState.ActiveSessionId.Reset();
	ActiveCompanionSpeechSessionState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
	ActiveCompanionSpeechSessionState.LastError.Reset();
	ActiveCompanionSpeechSessionState.MicrophoneShellState =
		HyperTwistTrainingSubsystemInternal::BuildCoachCommandMicrophoneShellState(
			ActiveCompanionSpeechSessionState.SessionConfig,
			&ActiveCompanionSpeechSessionState,
			false
		);
	ActiveCompanionSpeechSessionState.MicrophoneShellState.ActiveUtteranceId.Reset();
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bCaptureActive = false;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bAwaitingSpeech = false;
	ActiveCompanionSpeechSessionState.MicrophoneShellState.bTranscriptionInFlight = false;
	RefreshCompanionSpeechServiceHealth();
	return true;
}

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

bool UHyperTwistTrainingSubsystem::CanUseSmartDeviceBridge() const
{
	return HasActiveRun()
		&& ActiveRunState.Session.IsStructurallyValid()
		&& ActiveRunState.ActiveDeck.IsStructurallyValid()
		&& ActiveRunState.Session.Mode == EHyperTwistTrainingDeliveryMode::SmartDevice;
}

bool UHyperTwistTrainingSubsystem::TryResolveSmartDeviceAdapterBoundaryId(
	const FString& RequestedBoundaryId,
	FString& OutBoundaryId
) const
{
	OutBoundaryId.Reset();

	const FHyperTwistTrainingClassicCubingReferenceBundle ReferenceBundle =
		UHyperTwistTrainingClassicCubingLibrary::BuildBundledClassicCubingReferenceBundle();
	if (!ReferenceBundle.IsStructurallyValid())
	{
		return false;
	}

	const FString BoundaryId = !RequestedBoundaryId.IsEmpty()
		? RequestedBoundaryId
		: ReferenceBundle.PrimaryDeviceAdapterBoundaryId;
	FHyperTwistTrainingClassicCubingDeviceAdapterBoundary Boundary;
	if (!UHyperTwistTrainingClassicCubingLibrary::TryGetDeviceAdapterBoundaryById(
			ReferenceBundle,
			BoundaryId,
			Boundary))
	{
		return false;
	}

	OutBoundaryId = Boundary.BoundaryId;
	return !OutBoundaryId.IsEmpty();
}

FHyperTwistTrainingSmartDeviceIdentity UHyperTwistTrainingSubsystem::NormalizeSmartDeviceIdentity(
	const FHyperTwistTrainingSmartDeviceIdentity& DeviceIdentity
) const
{
	FHyperTwistTrainingSmartDeviceIdentity Normalized = DeviceIdentity;
	if (Normalized.ProviderId.IsEmpty() || Normalized.DeviceId.IsEmpty())
	{
		return FHyperTwistTrainingSmartDeviceIdentity();
	}
	if (Normalized.DeviceName.IsEmpty())
	{
		Normalized.DeviceName = Normalized.DeviceId;
	}

	FString ResolvedBoundaryId;
	if (!TryResolveSmartDeviceAdapterBoundaryId(Normalized.AdapterBoundaryId, ResolvedBoundaryId))
	{
		return FHyperTwistTrainingSmartDeviceIdentity();
	}

	Normalized.AdapterBoundaryId = ResolvedBoundaryId;
	Normalized.CapabilityTags.RemoveAll([](const FString& Value)
	{
		return Value.IsEmpty();
	});
	TArray<FString> UniqueCapabilityTags;
	for (const FString& CapabilityTag : Normalized.CapabilityTags)
	{
		UniqueCapabilityTags.AddUnique(CapabilityTag);
	}

	Normalized.CapabilityTags = MoveTemp(UniqueCapabilityTags);
	Normalized.CapabilityTags.Sort();
	return Normalized;
}

FHyperTwistTrainingSmartDeviceEventFrame UHyperTwistTrainingSubsystem::NormalizeSmartDeviceEventFrame(
	const FHyperTwistTrainingSmartDeviceEventFrame& EventFrame
) const
{
	FHyperTwistTrainingSmartDeviceEventFrame Normalized = EventFrame;
	Normalized.DeviceIdentity = NormalizeSmartDeviceIdentity(Normalized.DeviceIdentity);
	if (Normalized.EventId.IsEmpty() && Normalized.SequenceNumber >= 0)
	{
		Normalized.EventId = FString::Printf(TEXT("sequence-%lld"), Normalized.SequenceNumber);
	}

	if (Normalized.DeviceSessionId.IsEmpty())
	{
		Normalized.DeviceSessionId = ActiveSmartDeviceSessionRecord.DeviceSessionId;
	}
	if (Normalized.TrainingSessionId.IsEmpty())
	{
		Normalized.TrainingSessionId = ActiveRunState.Session.TrainingSessionId;
	}
	if (Normalized.UserId.IsEmpty())
	{
		Normalized.UserId = ActiveRunState.Session.UserId;
	}
	if (Normalized.DeckId.IsEmpty())
	{
		Normalized.DeckId = ActiveRunState.Session.DeckId;
	}
	if (Normalized.CaseId.IsEmpty())
	{
		Normalized.CaseId = ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid()
			? ActiveRunState.CurrentSelection.TrainingCase.CaseId
			: ActiveSmartDeviceSessionRecord.CaseId;
	}
	if (Normalized.OccurredAtUtc.IsEmpty())
	{
		Normalized.OccurredAtUtc = FDateTime::UtcNow().ToIso8601();
	}

	Normalized.TotalTimeMs = FMath::Max(0, Normalized.TotalTimeMs);
	Normalized.RawSolveTimeMs = FMath::Max(0, Normalized.RawSolveTimeMs);
	Normalized.InspectionElapsedMs = FMath::Max(0, Normalized.InspectionElapsedMs);
	Normalized.MistakeCount = FMath::Max(0, Normalized.MistakeCount);
	if (Normalized.RawSolveTimeMs == 0 && Normalized.TotalTimeMs > 0)
	{
		Normalized.RawSolveTimeMs = Normalized.TotalTimeMs;
	}
	if (Normalized.StatusReason.IsEmpty())
	{
		Normalized.StatusReason = TEXT("smart-device-event");
	}

	TArray<FHyperTwistTrainingSplitCapture> NormalizedSplitCaptures;
	TSet<FString> SeenSplitPhaseIds;
	for (FHyperTwistTrainingSplitCapture SplitCapture : Normalized.SplitCaptures)
	{
		if (!SplitCapture.IsStructurallyValid() || SeenSplitPhaseIds.Contains(SplitCapture.PhaseId))
		{
			continue;
		}

		SplitCapture.TimestampMs = FMath::Max(0, SplitCapture.TimestampMs);
		if (SplitCapture.Label.IsEmpty())
		{
			SplitCapture.Label = SplitCapture.PhaseId;
		}

		SeenSplitPhaseIds.Add(SplitCapture.PhaseId);
		NormalizedSplitCaptures.Add(SplitCapture);
	}
	NormalizedSplitCaptures.Sort([](
		const FHyperTwistTrainingSplitCapture& Left,
		const FHyperTwistTrainingSplitCapture& Right
	)
	{
		if (Left.TimestampMs != Right.TimestampMs)
		{
			return Left.TimestampMs < Right.TimestampMs;
		}

		return Left.PhaseId < Right.PhaseId;
	});
	Normalized.SplitCaptures = MoveTemp(NormalizedSplitCaptures);
	return Normalized;
}

FHyperTwistTrainingAttempt UHyperTwistTrainingSubsystem::BuildSmartDeviceAttemptFromEventFrame(
	const FHyperTwistTrainingSmartDeviceEventFrame& EventFrame
) const
{
	FHyperTwistTrainingAttempt Attempt;
	const FString CaseId = !EventFrame.CaseId.IsEmpty()
		? EventFrame.CaseId
		: (ActiveRunState.CurrentSelection.TrainingCase.IsStructurallyValid()
			? ActiveRunState.CurrentSelection.TrainingCase.CaseId
			: FString());
	if (!CanUseSmartDeviceBridge() || EventFrame.EventId.IsEmpty() || CaseId.IsEmpty())
	{
		return Attempt;
	}

	const EHyperTwistTrainingPenalty AppliedPenalty =
		EventFrame.AppliedPenalty != EHyperTwistTrainingPenalty::None
			? EventFrame.AppliedPenalty
			: (EventFrame.ManualPenalty != EHyperTwistTrainingPenalty::None
				? EventFrame.ManualPenalty
				: EventFrame.InspectionPenalty);
	const int32 RawSolveTimeMs = EventFrame.RawSolveTimeMs > 0
		? EventFrame.RawSolveTimeMs
		: EventFrame.TotalTimeMs;
	const int32 FinalTimeMs = EventFrame.TotalTimeMs > 0
		? EventFrame.TotalTimeMs
		: RawSolveTimeMs + HyperTwistTrainingSubsystemInternal::GetPenaltyOffsetMs(AppliedPenalty);

	Attempt.AttemptId = HyperTwistTrainingSubsystemInternal::BuildSmartDeviceAttemptId(
		ActiveRunState.Session.TrainingSessionId,
		EventFrame.EventId
	);
	Attempt.TrainingSessionId = ActiveRunState.Session.TrainingSessionId;
	Attempt.CaseId = CaseId;
	Attempt.Result = EventFrame.AttemptResult;
	Attempt.TotalTimeMs = FMath::Max(0, FinalTimeMs);
	Attempt.ExecutionTimeMs = FMath::Max(0, RawSolveTimeMs);
	Attempt.RecognitionTimeMs = 0;
	Attempt.TimingBreakdown.InspectionElapsedMs = EventFrame.InspectionElapsedMs;
	Attempt.TimingBreakdown.RawSolveTimeMs = FMath::Max(0, RawSolveTimeMs);
	Attempt.TimingBreakdown.PenaltyOffsetMs =
		HyperTwistTrainingSubsystemInternal::GetPenaltyOffsetMs(AppliedPenalty);
	Attempt.TimingBreakdown.FinalTimeMs = FMath::Max(0, FinalTimeMs);
	Attempt.TimingBreakdown.InspectionPenalty = EventFrame.InspectionPenalty;
	Attempt.TimingBreakdown.ManualPenalty = EventFrame.ManualPenalty;
	Attempt.TimingBreakdown.AppliedPenalty = AppliedPenalty;
	Attempt.TimingBreakdown.SplitCaptures = EventFrame.SplitCaptures;
	Attempt.TimingBreakdown.bDidNotFinish =
		EventFrame.AttemptResult == EHyperTwistTrainingAttemptResult::Timeout
		|| EventFrame.AttemptResult == EHyperTwistTrainingAttemptResult::DNF
		|| EventFrame.AttemptResult == EHyperTwistTrainingAttemptResult::Aborted;
	Attempt.Mistakes = EventFrame.MistakeCount;
	Attempt.ReplayId = !EventFrame.ReplayId.IsEmpty()
		? EventFrame.ReplayId
		: ActiveRunState.ReplayPacket.ReplayId;
	Attempt.CompletedAtUtc = EventFrame.OccurredAtUtc;
	return Attempt;
}

void UHyperTwistTrainingSubsystem::MergeSmartDeviceSplitCapturesIntoLiveTimer(
	const TArray<FHyperTwistTrainingSplitCapture>& SplitCaptures
)
{
	RefreshActiveLiveTimerState();
	if (!HasActiveLiveTimer())
	{
		return;
	}

	TSet<FString> SeenSplitPhaseIds;
	for (const FHyperTwistTrainingSplitCapture& ExistingSplitCapture : ActiveLiveTimerState.SplitCaptures)
	{
		if (!ExistingSplitCapture.PhaseId.IsEmpty())
		{
			SeenSplitPhaseIds.Add(ExistingSplitCapture.PhaseId);
		}
	}

	for (FHyperTwistTrainingSplitCapture SplitCapture : SplitCaptures)
	{
		if (!SplitCapture.IsStructurallyValid() || SeenSplitPhaseIds.Contains(SplitCapture.PhaseId))
		{
			continue;
		}

		SplitCapture.TimestampMs = FMath::Max(0, SplitCapture.TimestampMs);
		if (SplitCapture.Label.IsEmpty())
		{
			SplitCapture.Label = SplitCapture.PhaseId;
		}

		SeenSplitPhaseIds.Add(SplitCapture.PhaseId);
		ActiveLiveTimerState.SplitCaptures.Add(SplitCapture);
	}

	ActiveLiveTimerState.SplitCaptures.Sort([](
		const FHyperTwistTrainingSplitCapture& Left,
		const FHyperTwistTrainingSplitCapture& Right
	)
	{
		if (Left.TimestampMs != Right.TimestampMs)
		{
			return Left.TimestampMs < Right.TimestampMs;
		}

		return Left.PhaseId < Right.PhaseId;
	});
	ActiveLiveTimerState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
}

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;
	}
	if (HyperTwistTrainingSubsystemInternal::IsQbrClassicCubeRoute(SessionConfig))
	{
		if (SessionConfig.CalibrationProfile.IsEmpty()
			&& SessionConfig.CalibrationProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.CalibrationProfile = SessionConfig.CalibrationProfileDefinition.ProfileId;
		}
		if (SessionConfig.CalibrationProfile.IsEmpty())
		{
			SessionConfig.CalibrationProfile = TEXT("classic-cube-default");
		}
		if (!SessionConfig.CalibrationProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.CalibrationProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultClassicCubeCalibrationProfile(
					SessionConfig.CalibrationProfile
				);
		}
		if (SessionConfig.CalibrationProfileDefinition.ProfileId.IsEmpty())
		{
			SessionConfig.CalibrationProfileDefinition.ProfileId = SessionConfig.CalibrationProfile;
		}
		if (SessionConfig.ShellProfileId.IsEmpty()
			&& SessionConfig.ShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ShellProfileId = SessionConfig.ShellProfileDefinition.ShellProfileId;
		}
		if (SessionConfig.ShellProfileId.IsEmpty())
		{
			SessionConfig.ShellProfileId = TEXT("classic-cube-webcam-shell-v1");
		}
		if (!SessionConfig.ShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.ShellProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultClassicCubeWebcamShellProfile(
					SessionConfig.ShellProfileId
				);
		}
		if (SessionConfig.ShellProfileDefinition.ShellProfileId.IsEmpty())
		{
			SessionConfig.ShellProfileDefinition.ShellProfileId = SessionConfig.ShellProfileId;
		}
		if (SessionConfig.BrowserShellProfileId.IsEmpty()
			&& SessionConfig.BrowserShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.BrowserShellProfileId =
				SessionConfig.BrowserShellProfileDefinition.BrowserShellProfileId;
		}
		if (SessionConfig.BrowserShellProfileId.IsEmpty())
		{
			SessionConfig.BrowserShellProfileId = TEXT("classic-cube-browser-shell-v1");
		}
		if (!SessionConfig.BrowserShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.BrowserShellProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultClassicCubeBrowserShellProfile(
					SessionConfig.BrowserShellProfileId
				);
		}
		if (SessionConfig.BrowserShellProfileDefinition.BrowserShellProfileId.IsEmpty())
		{
			SessionConfig.BrowserShellProfileDefinition.BrowserShellProfileId =
				SessionConfig.BrowserShellProfileId;
		}
		if (SessionConfig.SolveExplanationProfileId.IsEmpty()
			&& SessionConfig.SolveExplanationProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.SolveExplanationProfileId =
				SessionConfig.SolveExplanationProfileDefinition.ExplanationProfileId;
		}
		if (SessionConfig.SolveExplanationProfileId.IsEmpty())
		{
			SessionConfig.SolveExplanationProfileId = TEXT("classic-cube-solve-explanation-v1");
		}
		if (!SessionConfig.SolveExplanationProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.SolveExplanationProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultClassicCubeSolveExplanationProfile(
					SessionConfig.SolveExplanationProfileId
				);
		}
		if (SessionConfig.SolveExplanationProfileDefinition.ExplanationProfileId.IsEmpty())
		{
			SessionConfig.SolveExplanationProfileDefinition.ExplanationProfileId =
				SessionConfig.SolveExplanationProfileId;
		}
		if (SessionConfig.CorrectionProfileId.IsEmpty()
			&& SessionConfig.CorrectionProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.CorrectionProfileId =
				SessionConfig.CorrectionProfileDefinition.CorrectionProfileId;
		}
		if (SessionConfig.CorrectionProfileId.IsEmpty())
		{
			SessionConfig.CorrectionProfileId = TEXT("classic-cube-correction-shell-v1");
		}
		if (!SessionConfig.CorrectionProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.CorrectionProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultClassicCubeCorrectionProfile(
					SessionConfig.CorrectionProfileId
				);
		}
		if (SessionConfig.CorrectionProfileDefinition.CorrectionProfileId.IsEmpty())
		{
			SessionConfig.CorrectionProfileDefinition.CorrectionProfileId =
				SessionConfig.CorrectionProfileId;
		}
	}

	return SessionConfig;
}

FHyperTwistSpeechSessionConfig UHyperTwistTrainingSubsystem::BuildActiveCompanionSpeechSessionConfig() const
{
	FHyperTwistSpeechSessionConfig SessionConfig = ActiveCompanionSpeechSessionState.SessionConfig;
	const bool bUseMockClient = CompanionSpeechClientKind.Equals(TEXT("mock"), ESearchCase::IgnoreCase);
	if (!HasActiveRun())
	{
		if (SessionConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty())
		{
			SessionConfig.NativeCaptureRouteWorkflowProfileId =
				TEXT("speech-native-capture-route-workflow-v1");
		}
		if (!SessionConfig.NativeCaptureRouteWorkflowProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.NativeCaptureRouteWorkflowProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultSpeechNativeCaptureRouteWorkflowProfile(
					SessionConfig.NativeCaptureRouteWorkflowProfileId
				);
		}
		if (SessionConfig.NativeCaptureRouteShellProfileId.IsEmpty())
		{
			SessionConfig.NativeCaptureRouteShellProfileId =
				TEXT("speech-native-capture-route-shell-v1");
		}
		if (!SessionConfig.NativeCaptureRouteShellProfileDefinition.IsStructurallyValid())
		{
			SessionConfig.NativeCaptureRouteShellProfileDefinition =
				HyperTwistTrainingSubsystemInternal::BuildDefaultSpeechNativeCaptureRouteShellProfile(
					SessionConfig.NativeCaptureRouteShellProfileId
				);
		}
		HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyDefaults(SessionConfig);
		HyperTwistTrainingSubsystemInternal::ApplySpeechExternalDictationDefaults(SessionConfig);
		HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileDefaults(
			SessionConfig,
			bUseMockClient
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechProviderRoutingDefaults(
			SessionConfig,
			bUseMockClient
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechUsageCostDefaults(SessionConfig);
		return SessionConfig;
	}

	const FHyperTwistTrainingCompanionReferenceBundle CompanionBundle =
		UHyperTwistTrainingRuntimeLibrary::GetBundledEmbodiedCompanionReferenceBundle();

	SessionConfig.SessionId = !ActiveCompanionSpeechSessionState.ActiveSessionId.IsEmpty()
		? ActiveCompanionSpeechSessionState.ActiveSessionId
		: HyperTwistTrainingSubsystemInternal::BuildSpeechSessionId(ActiveRunState.Session, 1);
	SessionConfig.ListeningContractId = !CompanionBundle.PrimaryListeningContractId.IsEmpty()
		? CompanionBundle.PrimaryListeningContractId
		: TEXT("listening-threshold-lifecycle");
	if (SessionConfig.InputRouteId.IsEmpty())
	{
		SessionConfig.InputRouteId = TEXT("queue/listening");
	}
	if (SessionConfig.AudioEncoding.IsEmpty())
	{
		SessionConfig.AudioEncoding = TEXT("pcm-f32le-16khz-mono");
	}
	if (SessionConfig.SampleRateHz <= 0)
	{
		SessionConfig.SampleRateHz = 16000;
	}
	if (SessionConfig.ChannelCount <= 0)
	{
		SessionConfig.ChannelCount = 1;
	}
	if (SessionConfig.LanguageMode.IsEmpty())
	{
		SessionConfig.LanguageMode = TEXT("auto");
	}
	if (SessionConfig.TaskKind.IsEmpty())
	{
		SessionConfig.TaskKind = TEXT("transcribe");
	}
	if (SessionConfig.GrammarProfileId.IsEmpty())
	{
		SessionConfig.GrammarProfileId = TEXT("coach-command-grammar-v1");
	}
	if (SessionConfig.MicrophoneShellProfileId.IsEmpty()
		&& SessionConfig.MicrophoneShellProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.MicrophoneShellProfileId =
			SessionConfig.MicrophoneShellProfileDefinition.MicrophoneShellProfileId;
	}
	if (SessionConfig.MicrophoneShellProfileId.IsEmpty())
	{
		SessionConfig.MicrophoneShellProfileId = TEXT("coach-command-microphone-shell-v1");
	}
	if (!SessionConfig.MicrophoneShellProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.MicrophoneShellProfileDefinition =
			HyperTwistTrainingSubsystemInternal::BuildDefaultCoachCommandMicrophoneShellProfile(
				SessionConfig.MicrophoneShellProfileId
			);
	}
	if (SessionConfig.MicrophoneShellProfileDefinition.MicrophoneShellProfileId.IsEmpty())
	{
		SessionConfig.MicrophoneShellProfileDefinition.MicrophoneShellProfileId =
			SessionConfig.MicrophoneShellProfileId;
	}
	if (SessionConfig.DevicePermissionWorkflowProfileId.IsEmpty()
		&& SessionConfig.DevicePermissionWorkflowProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.DevicePermissionWorkflowProfileId =
			SessionConfig.DevicePermissionWorkflowProfileDefinition
				.DevicePermissionWorkflowProfileId;
	}
	if (SessionConfig.DevicePermissionWorkflowProfileId.IsEmpty())
	{
		SessionConfig.DevicePermissionWorkflowProfileId =
			TEXT("speech-device-permission-workflow-v1");
	}
	if (!SessionConfig.DevicePermissionWorkflowProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.DevicePermissionWorkflowProfileDefinition =
			HyperTwistTrainingSubsystemInternal::BuildDefaultSpeechDevicePermissionWorkflowProfile(
				SessionConfig.DevicePermissionWorkflowProfileId
			);
	}
	if (SessionConfig.DevicePermissionWorkflowProfileDefinition.DevicePermissionWorkflowProfileId
		.IsEmpty())
	{
		SessionConfig.DevicePermissionWorkflowProfileDefinition.DevicePermissionWorkflowProfileId =
			SessionConfig.DevicePermissionWorkflowProfileId;
	}
	if (SessionConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty()
		&& SessionConfig.NativeCaptureRouteWorkflowProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.NativeCaptureRouteWorkflowProfileId =
			SessionConfig.NativeCaptureRouteWorkflowProfileDefinition
				.NativeCaptureRouteWorkflowProfileId;
	}
	if (SessionConfig.NativeCaptureRouteWorkflowProfileId.IsEmpty())
	{
		SessionConfig.NativeCaptureRouteWorkflowProfileId =
			TEXT("speech-native-capture-route-workflow-v1");
	}
	if (!SessionConfig.NativeCaptureRouteWorkflowProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.NativeCaptureRouteWorkflowProfileDefinition =
			HyperTwistTrainingSubsystemInternal::BuildDefaultSpeechNativeCaptureRouteWorkflowProfile(
				SessionConfig.NativeCaptureRouteWorkflowProfileId
			);
	}
	if (SessionConfig.NativeCaptureRouteWorkflowProfileDefinition
			.NativeCaptureRouteWorkflowProfileId.IsEmpty())
	{
		SessionConfig.NativeCaptureRouteWorkflowProfileDefinition
			.NativeCaptureRouteWorkflowProfileId =
				SessionConfig.NativeCaptureRouteWorkflowProfileId;
	}
	if (SessionConfig.NativeCaptureRouteShellProfileId.IsEmpty()
		&& SessionConfig.NativeCaptureRouteShellProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.NativeCaptureRouteShellProfileId =
			SessionConfig.NativeCaptureRouteShellProfileDefinition
				.NativeCaptureRouteShellProfileId;
	}
	if (SessionConfig.NativeCaptureRouteShellProfileId.IsEmpty())
	{
		SessionConfig.NativeCaptureRouteShellProfileId =
			TEXT("speech-native-capture-route-shell-v1");
	}
	if (!SessionConfig.NativeCaptureRouteShellProfileDefinition.IsStructurallyValid())
	{
		SessionConfig.NativeCaptureRouteShellProfileDefinition =
			HyperTwistTrainingSubsystemInternal::BuildDefaultSpeechNativeCaptureRouteShellProfile(
				SessionConfig.NativeCaptureRouteShellProfileId
			);
	}
	if (SessionConfig.NativeCaptureRouteShellProfileDefinition.NativeCaptureRouteShellProfileId
			.IsEmpty())
	{
		SessionConfig.NativeCaptureRouteShellProfileDefinition
			.NativeCaptureRouteShellProfileId =
				SessionConfig.NativeCaptureRouteShellProfileId;
	}
	HyperTwistTrainingSubsystemInternal::ApplySpeechExternalDictationDefaults(SessionConfig);
	SessionConfig.bEnableVad = true;
	if (!SessionConfig.VadPolicy.IsStructurallyValid())
	{
		SessionConfig.VadPolicy.Threshold = 0.5f;
		SessionConfig.VadPolicy.MinSpeechDurationMs = 250;
		SessionConfig.VadPolicy.MinSilenceDurationMs = 200;
		SessionConfig.VadPolicy.MaxSpeechDurationMs = 12000;
		SessionConfig.VadPolicy.SpeechPadMs = 100;
	}
	if (SessionConfig.OrchestrationProfile.OrchestrationProfileId.IsEmpty())
	{
		SessionConfig.OrchestrationProfile.OrchestrationProfileId = TEXT("python-batch-transcribe-v1");
	}
	if (SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty())
	{
		SessionConfig.OrchestrationProfile.ServiceLaneId = TEXT("speech/python-service");
	}
	if (SessionConfig.OrchestrationProfile.PreferredBatchSize <= 0)
	{
		SessionConfig.OrchestrationProfile.PreferredBatchSize = 8;
	}
	if (SessionConfig.OrchestrationProfile.ChunkLengthSeconds <= 0)
	{
		SessionConfig.OrchestrationProfile.ChunkLengthSeconds = 30;
	}
	if (SessionConfig.OrchestrationProfile.BatchCollectionWindowMs <= 0)
	{
		SessionConfig.OrchestrationProfile.BatchCollectionWindowMs = 150;
	}
	SessionConfig.OrchestrationProfile.bEnableBatchedInference = true;
	SessionConfig.OrchestrationProfile.bConditionOnPreviousText = false;
	SessionConfig.OrchestrationProfile.bEnableWordTimestamps = true;
	SessionConfig.OrchestrationProfile.bEnableLanguageDetection = true;
	SessionConfig.OrchestrationProfile.LanguageDetectionThreshold =
		FMath::Clamp(SessionConfig.OrchestrationProfile.LanguageDetectionThreshold, 0.0f, 1.0f);
	if (SessionConfig.OrchestrationProfile.LanguageDetectionSegmentCount <= 0)
	{
		SessionConfig.OrchestrationProfile.LanguageDetectionSegmentCount = 1;
	}
	if (SessionConfig.OrchestrationProfile.PromptRoutingModeId.IsEmpty())
	{
		SessionConfig.OrchestrationProfile.PromptRoutingModeId =
			TEXT("prefix-hotword-session-hints-v1");
	}
	if (SessionConfig.OrchestrationProfile.PrefixHint.IsEmpty())
	{
		SessionConfig.OrchestrationProfile.PrefixHint = TEXT("Coach command:");
	}
	if (SessionConfig.CommandHints.Num() <= 0)
	{
		SessionConfig.CommandHints = {
			TEXT("ready coach"),
			TEXT("repeat case"),
			TEXT("next case"),
			TEXT("pause coaching")
		};
	}
	if (SessionConfig.OrchestrationProfile.HotwordHints.Num() <= 0)
	{
		SessionConfig.OrchestrationProfile.HotwordHints = SessionConfig.CommandHints;
		SessionConfig.OrchestrationProfile.HotwordHints.Insert(TEXT("HyperTwist"), 0);
	}
	if (SessionConfig.OrchestrationProfile.RetrievalContextLaneId.IsEmpty())
	{
		SessionConfig.OrchestrationProfile.RetrievalContextLaneId =
			TEXT("speech-command-hint-session-memory");
	}
	if (SessionConfig.OrchestrationProfile.MaxRetrievedHintCount <= 0)
	{
		SessionConfig.OrchestrationProfile.MaxRetrievedHintCount = 4;
	}
	SessionConfig.OrchestrationProfile.bEnableRetrievedHintAugmentation = true;
	SessionConfig.bEnableWordTimestamps = SessionConfig.OrchestrationProfile.bEnableWordTimestamps;
	HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyDefaults(SessionConfig);
	HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileDefaults(
		SessionConfig,
		bUseMockClient
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechProviderRoutingDefaults(
		SessionConfig,
		bUseMockClient
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechUsageCostDefaults(SessionConfig);

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

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

	const bool bUseMockClient = CompanionSpeechClientKind.Equals(TEXT("mock"), ESearchCase::IgnoreCase);
	const bool bNeedsNewClient = ActiveCompanionSpeechClientObject == nullptr
		|| (bUseMockClient && !ActiveCompanionSpeechClientObject->IsA<UHyperTwistMockSpeechClient>())
		|| (!bUseMockClient && !ActiveCompanionSpeechClientObject->IsA<UHyperTwistHttpSpeechClient>());
	if (bNeedsNewClient)
	{
		if (bUseMockClient)
		{
			ActiveCompanionSpeechClientObject = NewObject<UHyperTwistMockSpeechClient>(this);
		}
		else
		{
			UHyperTwistHttpSpeechClient* HttpSpeechClient = NewObject<UHyperTwistHttpSpeechClient>(this);
			HttpSpeechClient->LoadConfig();
			ActiveCompanionSpeechClientObject = HttpSpeechClient;
		}
	}

	return ActiveCompanionSpeechClientObject;
}

void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth()
{
	IHyperTwistSpeechClient* SpeechClient = HyperTwistTrainingSubsystemInternal::ResolveSpeechClient(
		ResolveCompanionSpeechClientObject()
	);
	ActiveCompanionSpeechSessionState.bUsingProviderBackedClient =
		ActiveCompanionSpeechClientObject != nullptr
		&& ActiveCompanionSpeechClientObject->IsA<UHyperTwistHttpSpeechClient>();
	if (SpeechClient == nullptr)
	{
		ActiveCompanionSpeechSessionState.ServiceHealth = FHyperTwistSpeechServiceHealth();
		ActiveCompanionSpeechSessionState.ServiceHealth.ProviderLabel =
			ActiveCompanionSpeechSessionState.bUsingProviderBackedClient
				? TEXT("local-http-sidecar")
				: TEXT("mock");
		ActiveCompanionSpeechSessionState.ServiceHealth.ServiceEndpoint =
			ActiveCompanionSpeechSessionState.bUsingProviderBackedClient
				? TEXT("http://127.0.0.1:8766")
				: TEXT("in-process://mock");
		ActiveCompanionSpeechSessionState.ServiceHealth.bReady = false;
		ActiveCompanionSpeechSessionState.ServiceHealth.LastError = TEXT("speech-client-unavailable");
		HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileHealthDefaults(
			ActiveCompanionSpeechSessionState.ServiceHealth,
			ActiveCompanionSpeechSessionState.bUsingProviderBackedClient
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechProviderRoutingHealthDefaults(
			ActiveCompanionSpeechSessionState.ServiceHealth,
			&ActiveCompanionSpeechSessionState.SessionConfig,
			ActiveCompanionSpeechSessionState.bUsingProviderBackedClient,
			ActiveCompanionSpeechSessionState.LastError
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechUsageCostHealthDefaults(
			ActiveCompanionSpeechSessionState.ServiceHealth,
			&ActiveCompanionSpeechSessionState.SessionConfig,
			ActiveCompanionSpeechSessionState.LastError
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyHealthDefaults(
			ActiveCompanionSpeechSessionState.ServiceHealth
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechNativeCaptureRouteHealthDefaults(
			ActiveCompanionSpeechSessionState.ServiceHealth
		);
		HyperTwistTrainingSubsystemInternal::ApplySpeechExternalDictationHealthDefaults(
			ActiveCompanionSpeechSessionState.ServiceHealth
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechDevicePermissionWorkflowState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteWorkflowState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteShellState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechExternalDictationShellState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderReceiptReviewState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderBillingSettlementState(
			ActiveCompanionSpeechSessionState
		);
		HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderSettlementExceptionState(
			ActiveCompanionSpeechSessionState
		);
		return;
	}

	ActiveCompanionSpeechSessionState.ServiceHealth = SpeechClient->GetSpeechServiceHealth();
	HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileHealthDefaults(
		ActiveCompanionSpeechSessionState.ServiceHealth,
		ActiveCompanionSpeechSessionState.bUsingProviderBackedClient
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechProviderRoutingHealthDefaults(
		ActiveCompanionSpeechSessionState.ServiceHealth,
		&ActiveCompanionSpeechSessionState.SessionConfig,
		ActiveCompanionSpeechSessionState.bUsingProviderBackedClient,
		ActiveCompanionSpeechSessionState.LastError
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechUsageCostHealthDefaults(
		ActiveCompanionSpeechSessionState.ServiceHealth,
		&ActiveCompanionSpeechSessionState.SessionConfig,
		ActiveCompanionSpeechSessionState.LastError
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyHealthDefaults(
		ActiveCompanionSpeechSessionState.ServiceHealth
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechNativeCaptureRouteHealthDefaults(
		ActiveCompanionSpeechSessionState.ServiceHealth
	);
	HyperTwistTrainingSubsystemInternal::ApplySpeechExternalDictationHealthDefaults(
		ActiveCompanionSpeechSessionState.ServiceHealth
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechDevicePermissionWorkflowState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteWorkflowState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechNativeCaptureRouteShellState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechExternalDictationShellState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderReceiptReviewState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderBillingSettlementState(
		ActiveCompanionSpeechSessionState
	);
	HyperTwistTrainingSubsystemInternal::SynchronizeSpeechProviderSettlementExceptionState(
		ActiveCompanionSpeechSessionState
	);
}

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

void UHyperTwistTrainingSubsystem::ResetCompanionSpeechSessionState()
{
	ActiveCompanionSpeechSessionState = FHyperTwistTrainingCompanionSpeechSessionState();
	RefreshCompanionSpeechServiceHealth();
}

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();
		ActivePublicationBundle = FHyperTwistTrainingPublicationBundle();
		ActiveSocialChallengeBundle = FHyperTwistTrainingSocialChallengeBundle();
		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>();
	{
		const FHyperTwistTrainingKnowledgeReferenceBundle KnowledgeBundle =
			UHyperTwistTrainingKnowledgeLibrary::MakeHypercubingKnowledgeReferenceBundle();
		const FHyperTwistTrainingControlPlaneReferenceBundle ControlPlaneBundle =
			UHyperTwistTrainingControlPlaneLibrary::BuildBundledControlPlaneReferenceBundle();
		FHyperTwistTrainingFeatureGovernanceContract FeatureGovernanceContract;
		FHyperTwistTrainingEarlyAccessRolloutContract EarlyAccessContract;
		const bool bHasFeatureGovernanceContract =
			UHyperTwistTrainingControlPlaneLibrary::TryGetFeatureGovernanceContractById(
				ControlPlaneBundle,
				ControlPlaneBundle.PrimaryFeatureGovernanceContractId,
				FeatureGovernanceContract
			);
		const bool bHasEarlyAccessContract =
			UHyperTwistTrainingControlPlaneLibrary::TryGetEarlyAccessRolloutContractById(
				ControlPlaneBundle,
				ControlPlaneBundle.PrimaryEarlyAccessRolloutContractId,
				EarlyAccessContract
			);
		ActivePublicationBundle =
			RepositoryFocusDeck.IsStructurallyValid() && bHasFeatureGovernanceContract && bHasEarlyAccessContract
				? UHyperTwistTrainingPublicationLibrary::BuildPublicationBundle(
					ActiveLearnerProfile,
					ActiveDeckHistorySummary,
					ActivePersonalBestSummary,
					RepositoryFocusDeck,
					KnowledgeBundle,
					FeatureGovernanceContract,
					EarlyAccessContract
				)
				: FHyperTwistTrainingPublicationBundle();
	}
	ActiveSocialChallengeBundle = UHyperTwistTrainingRepositoryLibrary::DeriveSocialChallengeBundle(
		TrainingRepositoryState,
		RepositoryViewUserId,
		ResolvedReferenceUtc,
		ActivePublicationBundle.EntitlementGate
	);
	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
	);
}
