Restore carryover review action-plan continuity

This commit is contained in:
axiomlogicnexus 2026-05-07 20:29:00 +02:00
parent 006bef710f
commit a2d2f089bb
3 changed files with 243 additions and 3 deletions

View file

@ -1445,6 +1445,100 @@ namespace HyperTwistTrainingSubsystemInternal
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,
@ -3905,6 +3999,9 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReview
if (!HasActiveRun() && ActiveReviewPlanState.IsStructurallyValid())
{
const FHyperTwistTrainingReviewPlanState StoredReviewPlan = ActiveReviewPlanState;
const FHyperTwistTrainingCoachActionPlan StoredCoachActionPlan = ActiveCoachActionPlan;
const FHyperTwistCoachBrief StoredCoachBrief = ActiveCoachBrief;
const FHyperTwistCoachBrief StoredCoachFollowUpBrief = ActiveCoachFollowUpBrief;
const FHyperTwistTrainingDeck ReviewDeck = BuildActiveReviewDeck(MaxCases);
if (!ReviewDeck.IsStructurallyValid())
{
@ -3927,6 +4024,45 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReview
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
);
}
}
RefreshRepositoryViews();
return RunState;
}

View file

@ -66,9 +66,9 @@ Current correction call from the source-exposed audit and current execution refr
- retained benchmark-oracle and mirror-intake reservations
- current code reality in which training/coaching/catalog integration is materially ahead of recognition and hypercube runtime implementation
- the imported generated-mode gap is closed; request/config/selection plumbing and the bounded clean-room executor are already landed in first-party code
- the latest landed bounded `Phase 4` packet closes the dashboard template-launch analytics refinement lane above the already-landed recognition/review/queue continuity surfaces
- that closure now requires reinforced-vs-plain `DecisionSplitGuard` historical advantage before the final decision-bias snapshot guard can reinforce broader template-selection ties
- the current next bounded packet is the final full recognition-assisted coach-to-review closure validation pass across replay pressure, queue launch, post-clear review rehydration, post-clear action-plan rehydration, post-clear review resumption, final carryover consumption, review-program exhaustion, and truthful idle dashboard closure
- the latest landed bounded `Phase 4` packet closes the carryover-review action-plan resumption gap inside the already-live recognition-assisted coach-to-review continuity lane
- resumed idle carryover review launches now rebuild and activate a fresh coach action plan tied to the resumed session instead of dropping the carried-forward closure lineage at relaunch
- the current next bounded packet is to continue the same recognition-assisted coach-to-review closure validation pass from resumed carryover completion through final carryover consumption, review-program exhaustion, and truthful idle dashboard closure, landing only the next continuity fix that validation exposes
- the current execution-discipline rule that broad refactor / monolith-splitting work should not interrupt the active bounded roadmap packet unless structure is actually blocking it
## Current execution-reality references

View file

@ -0,0 +1,104 @@
# HyperTwist Phase 4 carryover review action-plan resumption continuity packet
Created on `2026-05-07`
Status:
- first-party HyperTwist packet
- bounded Phase `4` coach-to-review validation slice
## Purpose
This packet preserves coach action-plan continuity when an idle carryover review plan resumes after `ClearActiveRun()`.
The open tasks are:
- stop dropping the rehydrated coach action-plan lineage when `StartRecommendedReviewRun()` resumes a stored carryover review plan from idle state
- make the resumed carryover review session own a fresh active coach action plan tied to the resumed session so closure and outcome history advance truthfully
It is not:
- a new review-plan persistence packet
- a new queue-state packet
- a broader coach-brief redesign
- a dashboard command-surface rewrite
## Scope
Bounded lane:
- snapshot the stored review plan, coach briefs, and carry-forward action plan before `StartTrainingRunFromDeck()` clears transient coach state
- derive a carryover-review resume brief from the stored review plan, carried-forward action-plan lineage, and resumed review deck
- build, activate, and upsert a new coach action plan for the resumed carryover review session after the run launches
- keep the existing stored review-plan resumption path and true-idle closure behavior intact
Out of scope:
- changing review-plan scoring or completion rules
- changing queue execution ordering
- rewriting coach memory derivation
- widening into unrelated template analytics work
## Why this was the right next packet
Before this slice:
- post-clear action-plan rehydration was already landed
- post-clear review-plan resumption was already landed
- the subsystem could inspect and relaunch a stored carryover review plan from idle state
But one continuity seam still remained:
- `StartTrainingRunFromDeck()` correctly clears transient coach state before any new run
- the idle carryover review resumption path restored the stored review plan afterward
- but it did not attach a new active coach action plan to the resumed review session
That meant:
- carryover review execution could resume correctly
- while the resumed session itself no longer owned the action-plan lineage that downstream closure, outcome, and follow-up reconstruction expect
So the next honest move was:
- keep the stored review-plan resumption path
- and immediately rebuild a fresh active coach action plan for the resumed carryover review session from the carried-forward lineage
## What landed
Primary code changes:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp`
- added `BuildCarryoverReviewResumeBrief(...)` to rebuild a truthful resume brief from stored review-plan state, carried-forward action-plan lineage, and the relaunched review deck
- `StartRecommendedReviewRun()` now snapshots the stored coach briefs and carried-forward action plan before launching the resumed carryover review run
- after launch, it builds `coach_carryover_review_<session>` as a fresh action plan, activates it against the resumed session id, upserts it into repository state, and then refreshes repository views
## Product effect
The post-clear carryover lane is now more truthful:
- resumed carryover review runs keep a live coach action plan instead of silently dropping action-plan lineage at the relaunch boundary
- resumed-session closure and outcome history now attach to the resumed review session rather than relying only on stale pre-resume plan context
- follow-up and idle reconstruction after the resumed review can keep using the correct carry-forward lineage until carryover is genuinely exhausted
## Acceptance criteria
- when an idle stored carryover review plan resumes, the subsystem creates a fresh active coach action plan if a carried-forward plan lineage exists
- that resumed action plan preserves parent/root review lineage and review focus context
- repository state stores the resumed action plan before the final repository refresh
- full product build succeeds
## Validation checklist
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
2. confirm idle `StartRecommendedReviewRun()` snapshots stored coach action state before `StartTrainingRunFromDeck()` clears it
3. confirm resumed carryover review launch builds and activates `coach_carryover_review_<session>`
4. confirm the resumed action plan preserves carry-forward lineage while using the resumed session id as the active source session
5. confirm no broader queue/dashboard redesign was reopened
## Validation result
- full `Development Editor|Win64` build succeeded on `2026-05-07`
## Next bounded follow-on slice
- continue the same recognition-assisted coach-to-review closure validation pass from resumed carryover completion through final carryover consumption, review-program exhaustion, and truthful idle dashboard closure, and land only the next continuity fix that pass exposes