Restore carryover review queue execution continuity

This commit is contained in:
axiomlogicnexus 2026-05-07 20:42:28 +02:00
parent a2d2f089bb
commit 63d0b37594
3 changed files with 239 additions and 3 deletions

View file

@ -1199,6 +1199,100 @@ namespace HyperTwistTrainingSubsystemInternal
);
}
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,
@ -4002,6 +4096,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReview
const FHyperTwistTrainingCoachActionPlan StoredCoachActionPlan = ActiveCoachActionPlan;
const FHyperTwistCoachBrief StoredCoachBrief = ActiveCoachBrief;
const FHyperTwistCoachBrief StoredCoachFollowUpBrief = ActiveCoachFollowUpBrief;
const FHyperTwistTrainingCoachSessionQueueState StoredCoachQueueState = ActiveCoachSessionQueueState;
const FHyperTwistTrainingDeck ReviewDeck = BuildActiveReviewDeck(MaxCases);
if (!ReviewDeck.IsStructurallyValid())
{
@ -4063,6 +4158,45 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReview
);
}
}
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;
}

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 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 latest landed bounded `Phase 4` packet closes the carryover-review queue execution gap inside the already-live recognition-assisted coach-to-review continuity lane
- resumed idle carryover review launches now bind back onto any matching live queue entry so completion can close the same queue lineage that the resumed session actually consumed
- the current next bounded packet is to continue the same recognition-assisted coach-to-review closure validation pass from queue-backed 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,102 @@
# HyperTwist Phase 4 carryover review queue execution continuity packet
Created on `2026-05-07`
Status:
- first-party HyperTwist packet
- bounded Phase `4` coach-to-review validation slice
## Purpose
This packet preserves queue execution lineage when an idle carryover review plan resumes after `ClearActiveRun()`.
The open tasks are:
- stop relaunching a stored carryover review plan without advancing any matching live coach queue entry in repository state
- let resumed carryover review completion close the same queue lineage it actually consumed so queue execution history, schedule feedback, and final idle collapse stay truthful
It is not:
- a new review-plan persistence packet
- a new action-plan packet
- a broader queue-priority redesign
- a dashboard layout rewrite
## Scope
Bounded lane:
- inspect the stored live coach queue state before idle carryover review relaunch
- resolve the best matching queue entry from review-plan lineage, carry-forward action-plan lineage, and relaunched review cases
- mark that queue entry started against the resumed review session before the final repository refresh
- leave queue state untouched when no matching live repository queue entry exists
Out of scope:
- changing how review plans are scored or finalized
- changing queue ordering heuristics
- rewriting coach follow-up derivation
- widening into unrelated analytics or template-selection work
## Why this was the right next packet
Before this slice:
- idle carryover review resumption was already landed
- resumed carryover review launches already rebuilt a fresh active coach action plan tied to the resumed session
But one continuity seam still remained:
- the resumed carryover review launch could restore review-plan lineage and action-plan lineage
- while any matching live coach queue entry still remained unstarted in repository state
That meant:
- the resumed session could consume carryover review work correctly
- while queue execution history and queue-derived closure feedback still had no truthful started session to close against that relaunched work
So the next honest move was:
- keep the resumed review relaunch logic
- and bind it back onto the matching live queue entry when that queue lineage actually exists
## What landed
Primary code changes:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp`
- added `FindCarryoverResumeQueueEntry(...)` to match a live queue entry from stored review-plan id, carry-forward/root plan lineage, and relaunched review cases
- idle `StartRecommendedReviewRun()` now snapshots the pre-relaunch queue state
- after relaunch, it resolves the current repository queue state, marks the matched entry started with the resumed session id via `StartCoachSessionQueueEntryById(...)`, upserts it, and then refreshes repository views
## Product effect
The resumed carryover closure lane is now more truthful:
- queue-backed carryover review relaunches no longer bypass queue execution lineage
- resumed carryover review completion can now finalize the same queue entry by session id instead of leaving queue execution history blind to the relaunch
- queue-derived schedule and closure feedback have a cleaner path back to true idle once the final carryover slice is actually consumed
## Acceptance criteria
- when a stored idle carryover review plan relaunches and a matching live queue entry exists, that queue entry is marked started against the resumed session
- when no matching live queue entry exists, the relaunch leaves queue state untouched
- the resumed queue entry remains repository-backed so completion can finalize it by session id
- full product build succeeds
## Validation checklist
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
2. confirm idle `StartRecommendedReviewRun()` snapshots the pre-relaunch queue state
3. confirm a matching live repository queue entry is resolved from review-plan / carry-forward lineage before queue mutation
4. confirm resumed carryover relaunch marks that queue entry started with the resumed session id
5. confirm no broader queue-priority or 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 queue-backed resumed carryover completion through final carryover consumption, review-program exhaustion, and truthful idle dashboard closure, and land only the next continuity fix that validation exposes