Persist method drill review follow-up plans
This commit is contained in:
parent
f28f6df06d
commit
89a37bce08
2 changed files with 217 additions and 21 deletions
|
|
@ -1348,6 +1348,19 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
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,
|
||||
|
|
@ -1364,8 +1377,8 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (!SessionTemplate.SourceReviewPlanId.IsEmpty()
|
||||
&& SessionTemplate.SourceReviewPlanId != ReviewPlan.PlanId)
|
||||
if (SessionTemplate.SourceReviewPlanId.IsEmpty()
|
||||
|| SessionTemplate.SourceReviewPlanId != ReviewPlan.PlanId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1378,6 +1391,42 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -3577,25 +3626,16 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromTe
|
|||
FHyperTwistTrainingDeck SourceDeck;
|
||||
FHyperTwistTrainingReviewPolicy ReviewPolicy;
|
||||
TArray<FHyperTwistTrainingCaseRecommendation> TemplateRecommendations;
|
||||
if (MatchingTemplate->bPreferReviewRun
|
||||
&& UHyperTwistTrainingCatalogLibrary::TryFindDeckInCatalog(
|
||||
UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog(),
|
||||
MatchingTemplate->FocusDeckId,
|
||||
SourceDeck))
|
||||
{
|
||||
ReviewPolicy = HyperTwistTrainingSubsystemInternal::BuildTemplateReviewPolicy(
|
||||
const bool bPreparedReviewTemplateLaunch =
|
||||
HyperTwistTrainingSubsystemInternal::TryPrepareReviewPlanBackedTemplateLaunch(
|
||||
TrainingRepositoryState,
|
||||
*MatchingTemplate,
|
||||
MaterializedDeck.Cases.Num()
|
||||
MaterializedDeck,
|
||||
ResolvedUserId,
|
||||
SourceDeck,
|
||||
ReviewPolicy,
|
||||
TemplateRecommendations
|
||||
);
|
||||
TemplateRecommendations =
|
||||
HyperTwistTrainingSubsystemInternal::BuildTemplateReviewRecommendations(
|
||||
TrainingRepositoryState,
|
||||
SourceDeck,
|
||||
MaterializedDeck,
|
||||
ResolvedUserId,
|
||||
*MatchingTemplate
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
|
||||
MaterializedDeck,
|
||||
|
|
@ -3605,7 +3645,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromTe
|
|||
);
|
||||
if (!RunState.IsStructurallyValid()
|
||||
|| !MatchingTemplate->bPreferReviewRun
|
||||
|| !SourceDeck.IsStructurallyValid())
|
||||
|| !bPreparedReviewTemplateLaunch)
|
||||
{
|
||||
return RunState;
|
||||
}
|
||||
|
|
@ -3667,12 +3707,72 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartActiveMethodDrill
|
|||
*ResolvedSessionId,
|
||||
*MethodDrillPacketStructureToken)
|
||||
: ResolvedSessionId;
|
||||
return StartTrainingRunFromDeck(
|
||||
|
||||
if (HyperTwistTrainingSubsystemInternal::ShouldResumeStoredReviewPlanFromTemplate(
|
||||
ActiveMethodDrillFollowUpTemplate,
|
||||
ActiveReviewPlanState,
|
||||
ActiveMethodDrillRunState.UserId))
|
||||
{
|
||||
return StartRecommendedReviewRun(
|
||||
StructuredSessionId,
|
||||
FollowUpDeck.Cases.Num(),
|
||||
ActiveMethodDrillFollowUpTemplate.SuggestedMode
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
if (!RunState.IsStructurallyValid()
|
||||
|| !ActiveMethodDrillFollowUpTemplate.bPreferReviewRun
|
||||
|| !bPreparedReviewTemplateLaunch)
|
||||
{
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
# HyperTwist Phase 4 method-drill review template continuity packet
|
||||
|
||||
Created on `2026-05-06`
|
||||
|
||||
Status:
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- bounded Phase `4` method-drill follow-up review slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet closes the remaining review-template continuity gap on the method-drill follow-up launch path.
|
||||
|
||||
The open tasks are:
|
||||
|
||||
- stop treating method-drill follow-up templates that prefer review execution as plain deck runs
|
||||
- tighten stored review-plan resumption so only explicit pending-plan templates resume an already-open plan
|
||||
|
||||
It is not:
|
||||
|
||||
- a new drill diagnostic packet
|
||||
- a broader dashboard launch-surface packet
|
||||
- a rewrite of review-template construction
|
||||
- a queue / coach orchestration packet
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- keep the existing method-drill follow-up template builder unchanged
|
||||
- reuse the same review-template launch preparation logic now used by generic session templates
|
||||
- make `StartActiveMethodDrillFollowUpRun()` persist review-plan state when its follow-up template prefers review execution
|
||||
- require `SourceReviewPlanId` on template-backed stored-plan resume so generic review-preferring templates only resume when they explicitly target the open plan
|
||||
|
||||
Out of scope:
|
||||
|
||||
- widening into unrelated method-drill diagnostic heuristics
|
||||
- changing review-plan scoring rules
|
||||
- adding new template browsing or launch buttons
|
||||
- changing follow-up packet structure selection
|
||||
|
||||
## Why this was the right next packet
|
||||
|
||||
Before this slice:
|
||||
|
||||
- generic session templates that preferred review execution already launched through review-plan semantics
|
||||
- method-drill follow-up templates already set `bPreferReviewRun` when their diagnostic packet asked for a review-plan bridge
|
||||
|
||||
But two seams still remained:
|
||||
|
||||
- `StartActiveMethodDrillFollowUpRun()` still launched those follow-up templates through `StartTrainingRunFromDeck()` only
|
||||
- and the new stored-plan resume helper was broad enough to resume any open plan on the same deck, even when the template did not explicitly target that plan
|
||||
|
||||
That meant:
|
||||
|
||||
- generic template review continuity had landed
|
||||
- while method-drill follow-up review continuity still lagged behind it
|
||||
- and the stored-plan resume path still needed a tighter contract to match the last packet’s intended behavior
|
||||
|
||||
So the next honest move was:
|
||||
|
||||
- narrow stored-plan resume down to explicit `SourceReviewPlanId` matches
|
||||
- then extend review-plan persistence into method-drill follow-up launches using that safer rule
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp`
|
||||
- tightened template-backed stored-plan resume matching so only explicit pending-plan templates resume an already-open plan
|
||||
- added shared review-template launch preparation for source-deck lookup, review policy, and template-backed recommendations
|
||||
- `StartActiveMethodDrillFollowUpRun()` now persists a review plan after launch when the active follow-up template prefers review execution
|
||||
|
||||
## Product effect
|
||||
|
||||
The review-template lane is now more coherent:
|
||||
|
||||
- `Resume Review Plan` keeps its direct stored-plan resumption path
|
||||
- other review-preferring templates no longer accidentally reuse an unrelated open plan just because they share the same focus deck
|
||||
- method-drill follow-up launches now keep repository-backed review state aligned with the review-preferring template that launched them
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- template-backed stored-plan resume only occurs when the template explicitly names the open review plan
|
||||
- method-drill follow-up templates with `bPreferReviewRun` persist a review plan after launch
|
||||
- method-drill follow-up templates without review preference keep their existing plain-run behavior
|
||||
- full product build succeeds
|
||||
|
||||
## Validation checklist
|
||||
|
||||
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
|
||||
2. confirm generic review-preferring templates without `SourceReviewPlanId` no longer resume arbitrary open plans
|
||||
3. confirm `StartActiveMethodDrillFollowUpRun()` persists review-plan state when the follow-up template prefers review execution
|
||||
4. confirm non-review method-drill follow-up launches still behave as ordinary training runs
|
||||
|
||||
That is the packet.
|
||||
Loading…
Add table
Reference in a new issue