Retire stale queue state after run clear

This commit is contained in:
axiomlogicnexus 2026-05-06 19:36:21 +02:00
parent c7e02fe1cd
commit b361794457
4 changed files with 150 additions and 2 deletions

View file

@ -21232,6 +21232,27 @@ FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::UpsertC
return UpdatedRepositoryState;
}
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::RemoveCoachSessionQueueState(
const FHyperTwistTrainingRepositoryState& RepositoryState,
const FString& UserId,
const FString& QueueId
)
{
if (UserId.IsEmpty() || QueueId.IsEmpty())
{
return RepositoryState;
}
FHyperTwistTrainingRepositoryState UpdatedRepositoryState = RepositoryState;
UpdatedRepositoryState.StoredCoachSessionQueues.RemoveAll(
[&UserId, &QueueId](const FHyperTwistTrainingCoachSessionQueueState& Candidate)
{
return Candidate.UserId == UserId && Candidate.QueueId == QueueId;
}
);
return UpdatedRepositoryState;
}
FHyperTwistTrainingCoachSessionQueueExecutionSummary UHyperTwistTrainingRepositoryLibrary::DeriveCoachSessionQueueExecutionSummary(
const FHyperTwistTrainingRepositoryState& RepositoryState,
const FString& UserId,

View file

@ -3372,7 +3372,11 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReview
return FHyperTwistTrainingRunState();
}
const FString UserId = ActiveRunState.Session.UserId.IsEmpty() ? TEXT("local-user") : ActiveRunState.Session.UserId;
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())
{
@ -3417,7 +3421,11 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachRecommendedR
return FHyperTwistTrainingRunState();
}
const FString UserId = ActiveRunState.Session.UserId.IsEmpty() ? TEXT("local-user") : ActiveRunState.Session.UserId;
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(
@ -5302,6 +5310,17 @@ void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
}
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();

View file

@ -476,6 +476,13 @@ public:
const FHyperTwistTrainingCoachSessionQueueState& QueueState
);
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Coach")
static FHyperTwistTrainingRepositoryState RemoveCoachSessionQueueState(
const FHyperTwistTrainingRepositoryState& RepositoryState,
const FString& UserId,
const FString& QueueId
);
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Coach")
static FHyperTwistTrainingCoachSessionQueueExecutionSummary DeriveCoachSessionQueueExecutionSummary(
const FHyperTwistTrainingRepositoryState& RepositoryState,

View file

@ -0,0 +1,101 @@
# HyperTwist Phase 4 post-clear queue idle continuity packet
Created on `2026-05-06`
Status:
- first-party HyperTwist packet
- bounded Phase `4` coach-to-review validation slice
## Purpose
This packet closes the next post-clear execution gap in the live recognition-assisted coach-to-review loop.
The open tasks are:
- keep post-clear recovered coach launches bound to the retained learner instead of silently falling back to `local-user`
- retire the stored active queue state when carryover-backed queue work is actually exhausted, so queue-recovery bias can collapse back to a truthful idle posture
It is not:
- a new queue-priority heuristic packet
- a broader recommendation-history redesign
- a new dashboard layout packet
- a recognition transport packet
## Scope
Bounded lane:
- fix recovered recommended/review launches so they inherit the retained coach user context
- add repository support for removing the active coach queue state without deleting queue history
- clear the stored active queue state when repository-derived queue summary no longer materializes any live queue work
- keep queue history intact so execution analytics and lineage remain available
Out of scope:
- new review scoring
- queue-history pruning
- broad coach-memory retuning
- structural cleanup beyond the narrow queue retirement seam
## Why this was the right next packet
Before this slice:
- clear-run repository-view continuity was already landed
- post-clear coach guidance and queue state could survive the run-clear boundary
- queue history and queue-derived recovery signals were already part of coach-memory shaping
But two post-clear mismatches still remained:
- `StartCoachRecommendedRun()` still defaulted to `local-user` whenever there was no active run, even if the recovered coach brief already carried the correct retained user
- when queue summary no longer produced any live queue work, the subsystem cleared only the in-memory queue state; the repository still retained the last active queue state
That meant:
- recovered recommended coach runs could bind to the wrong learner after run clear
- queue-recovery bias could stay live in repository-derived coach memory because `DeriveQueueRecoveryBiasSnapshot()` still found a stored active queue state even after the queue should have collapsed to idle
So the next honest move was:
- align recovered launch ownership with retained coach context and retire the stored active queue state once the live queue actually disappears
## What landed
Primary code changes:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h`
- added repository support for removing an active coach queue state by `UserId` and `QueueId`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp`
- implemented `RemoveCoachSessionQueueState()` without touching queue history
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp`
- recovered recommended/review launch paths now prefer retained coach user context before falling back to `local-user`
- repository refresh now removes the stored active queue state when no live queue summary remains materialized
## Product effect
The post-clear execution lane is now more truthful:
- recovered coach launches stay attached to the retained learner identity
- once carryover-backed queue work is gone, the stored active queue state no longer keeps queue-recovery bias artificially alive
- queue history remains available for analytics, but active queue posture can return cleanly to idle
- dashboard and coach-memory surfaces have a cleaner path back to “no active queue work” after carryover is actually consumed
## Acceptance criteria
- post-clear recovered recommended/review launches no longer fall back to `local-user` when retained coach user context exists
- stored active queue state is removed when repository-derived queue summary no longer materializes live queue work
- queue history is preserved while active queue state is retired
- repository-derived queue recovery bias can collapse after true queue exhaustion
- full product build succeeds
## Validation checklist
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
2. confirm recovered recommended/review launch paths prefer retained coach user context
3. confirm repository refresh removes the active queue state when queue summary is no longer structurally valid
4. confirm queue history remains untouched
5. confirm no broader queue or coach-memory redesign was reopened
That is the packet.