Surface recognition handoff state in coach dashboard

This commit is contained in:
axiomlogicnexus 2026-05-06 04:38:25 +02:00
parent 44ecb902a0
commit 233bc1627f
5 changed files with 166 additions and 0 deletions

View file

@ -5540,6 +5540,18 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
TEXT("CoachQueueSuppressionHistoryDetail"),
8
);
RecognitionStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
RootLayout,
TEXT("CoachRecognitionStatus"),
2
);
RecognitionDetailTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
RootLayout,
TEXT("CoachRecognitionDetail"),
8
);
VerificationStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
RootLayout,
@ -15619,6 +15631,14 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
{
VerificationStatusTextBlock->SetText(FText::FromString(CachedCoachPanelState.VerificationStatusLine));
}
if (RecognitionStatusTextBlock != nullptr)
{
RecognitionStatusTextBlock->SetText(FText::FromString(CachedCoachPanelState.RecognitionStatusLine));
}
if (RecognitionDetailTextBlock != nullptr)
{
RecognitionDetailTextBlock->SetText(FText::FromString(CachedCoachPanelState.RecognitionDetailLine));
}
if (VerificationHeaderTextBlock != nullptr)
{
VerificationHeaderTextBlock->SetText(FText::FromString(TEXT("[Repository Verification]")));

View file

@ -1260,6 +1260,11 @@ namespace HyperTwistTrainingSubsystemInternal
}
return Count;
}
FString FormatRecognitionConfidence(const float Value)
{
return Value >= 0.0f ? FString::Printf(TEXT("%.2f"), Value) : TEXT("n/a");
}
}
bool UHyperTwistTrainingSubsystem::HasActiveRun() const
@ -2122,6 +2127,39 @@ FHyperTwistTrainingCoachPanelState UHyperTwistTrainingSubsystem::GetActiveCoachP
*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 | Finalizations %d"),
*RecognitionProviderLabel,
*RecognitionTransportState,
ActiveRecognitionSessionState.bSessionOpen ? TEXT("open") : TEXT("closed"),
ActiveRecognitionSessionState.SubmittedFrameCount,
ActiveRecognitionSessionState.CommittedObservationCount,
ActiveRecognitionSessionState.CorrectionEventCount,
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")
);
PanelState.VerificationStatusLine = ActiveRepositoryRoundTripVerification.ResolvedPath.IsEmpty()
? TEXT("Verification: not run yet")
: (ActiveRepositoryRoundTripVerification.bDidRoundTripPass

View file

@ -1142,6 +1142,12 @@ protected:
UPROPERTY(Transient)
TObjectPtr<UTextBlock> NextQueueSuppressionButtonLabel = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> RecognitionStatusTextBlock = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> RecognitionDetailTextBlock = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> VerificationStatusTextBlock = nullptr;

View file

@ -6801,6 +6801,12 @@ struct FHyperTwistTrainingCoachPanelState
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString VerificationStatusLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecognitionStatusLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecognitionDetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHasLatestGeneratedModeLaunchRequest = false;

View file

@ -0,0 +1,96 @@
# HyperTwist Phase 4 recognition handoff inspection packet
Created on `2026-05-06`
Status:
- first-party HyperTwist packet
- bounded Phase `4` recognition inspection slice
## Purpose
This packet closes the next honest step after the recognition runtime handoff landed.
The open task is:
- surface live recognition provider/session/replay-handoff state through the existing coach-panel and dashboard inspection path
It is not:
- a large recognition UI rewrite
- another backend productionization packet
- a speech or simulation packet
- a general dashboard redesign
## Scope
Bounded lane:
- extend `FHyperTwistTrainingCoachPanelState` with recognition inspection lines
- derive those lines from:
- recognition service health
- recognition session runtime state
- recognition replay summary
- coach preference state already derived from replay/coaching logic
- show those lines in the coach dashboard using the existing text-row inspection pattern
Out of scope:
- new recognition controls
- transport/protocol changes
- broader coach-surface layout work
- reopening the recognition runtime handoff backend
## Why this was the right next packet
Before this slice:
- the owned recognition runtime handoff was live
- replay/training/coaching state could already rebuild from recognition replay mutation
- but the live product did not expose that state coherently through its main inspection surface
So the next bounded need was:
- make the runtime handoff visible where the current product already inspects coaching/runtime state
## What landed
Primary code changes:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
- added recognition inspection lines to `FHyperTwistTrainingCoachPanelState`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp`
- coach-panel state now emits:
- recognition provider / service / session / counter summary
- recognition replay / ambiguity / coach-preference handoff summary
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h`
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp`
- dashboard now renders the new recognition inspection lines with the existing text-row surface
## Product effect
The first-party coach dashboard can now show:
- which recognition provider lane is active
- whether the provider currently reports ready or blocked transport state
- whether a recognition session is open
- cumulative frame / commit / correction / finalize counts
- recognition replay episode and ambiguity counts
- whether coach guidance is currently recognition-review biased
That makes the already-landed runtime handoff inspectable without widening the backend again.
## Acceptance criteria
- coach-panel state exposes live recognition runtime and replay-handoff inspection lines
- the coach dashboard renders those lines
- no recognition backend contract or runtime ownership packet is reopened
- full product build succeeds
## Validation checklist
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
2. confirm the updated panel-state struct, subsystem assembly, and dashboard widget all compile together
3. confirm the packet stays bounded to inspection/surfacing rather than changing recognition transport behavior
That is the packet.