Expose comparable peer confidence lanes

This commit is contained in:
axiomlogicnexus 2026-05-07 02:28:42 +02:00
parent badbd4a082
commit 313aa01cec
2 changed files with 195 additions and 1 deletions

View file

@ -121,6 +121,10 @@ namespace HyperTwistCoachDashboardWidgetInternal
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
FString BuildTemplateLaunchComparablePeerConfidenceLaneFragment(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
bool HasTemplateLaunchComparablePeerEvidenceForConfidenceBonus(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutComparablePeerOutcomeRuns = nullptr,
@ -153,7 +157,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
}
return FString::Printf(
TEXT("avg recommended %d | avg focus %d | avg completed attempts %d | total success/failure/timeout/dnf %d/%d/%d/%d | avg mistakes %.2f | review-backed %d | coach-review %d | short set %d | selector split %s | tie-break support %s | peer support split %s | last launch %s | last completed %s"),
TEXT("avg recommended %d | avg focus %d | avg completed attempts %d | total success/failure/timeout/dnf %d/%d/%d/%d | avg mistakes %.2f | review-backed %d | coach-review %d | short set %d | selector split %s | tie-break support %s | peer support split %s | comparable-peer confidence %s | last launch %s | last completed %s"),
TemplateStats->AverageRecommendedCaseCount,
TemplateStats->AverageFocusCaseCount,
TemplateStats->AverageCompletedAttemptCount,
@ -168,6 +172,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
*BuildTemplateLaunchSelectionSplitAnalyticsFragment(TemplateStats),
*BuildTemplateLaunchAnalyticsTieBreakSupportSplitFragment(TemplateStats),
*BuildTemplateLaunchAnalyticsTieBreakPeerDispositionSplitFragment(TemplateStats),
*BuildTemplateLaunchComparablePeerConfidenceLaneFragment(TemplateStats),
TemplateStats->LastLaunchAtUtc.IsEmpty()
? TEXT("n/a")
: *TemplateStats->LastLaunchAtUtc,
@ -536,6 +541,128 @@ namespace HyperTwistCoachDashboardWidgetInternal
);
}
FString BuildTemplateLaunchComparablePeerConfidenceLaneFragment(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
)
{
if (TemplateStats == nullptr || !TemplateStats->IsStructurallyValid())
{
return TEXT("no comparable-peer confidence lane is available for this template id yet");
}
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& SplitConfidenceStats =
TemplateStats->DashboardAnalyticsTieBreakSelectorSplitConfidenceStats;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& PeerNoEvidenceStats =
TemplateStats
->DashboardAnalyticsTieBreakSelectorSplitConfidencePeerLackedComparableEvidenceStats;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& PeerWeakerStats =
TemplateStats
->DashboardAnalyticsTieBreakSelectorSplitConfidencePeerFailedWeakerSupportKindStats;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& PeerMarginalStats =
TemplateStats
->DashboardAnalyticsTieBreakSelectorSplitConfidencePeerFailedMarginalSupportKindStats;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& PeerClearedStats =
TemplateStats
->DashboardAnalyticsTieBreakSelectorSplitConfidencePeerClearedComparableGuardStats;
if (!SplitConfidenceStats.IsStructurallyValid()
&& !PeerNoEvidenceStats.IsStructurallyValid()
&& !PeerWeakerStats.IsStructurallyValid()
&& !PeerMarginalStats.IsStructurallyValid()
&& !PeerClearedStats.IsStructurallyValid())
{
return TEXT("no comparable-peer confidence lane is available for this template id yet");
}
auto BuildCombinedLaneSummary =
[](
const TCHAR* LaneLabel,
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* FirstStats,
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* SecondStats,
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* ThirdStats)
{
int32 LaunchCount = 0;
int32 OutcomeRunCount = 0;
int32 TotalCompletedAttemptCount = 0;
int32 TotalSuccessCount = 0;
double MistakeAccumulator = 0.0;
bool bHasAnyStats = false;
auto AccumulateStats =
[&](
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* SourceStats)
{
if (SourceStats == nullptr || !SourceStats->IsStructurallyValid())
{
return;
}
bHasAnyStats = true;
LaunchCount += SourceStats->LaunchCount;
OutcomeRunCount += SourceStats->GetOutcomeRunCount();
TotalCompletedAttemptCount += SourceStats->TotalCompletedAttemptCount;
TotalSuccessCount += SourceStats->TotalSuccessCount;
MistakeAccumulator += static_cast<double>(
SourceStats->AverageMistakesPerOutcomeRun)
* static_cast<double>(SourceStats->GetOutcomeRunCount());
};
AccumulateStats(FirstStats);
AccumulateStats(SecondStats);
AccumulateStats(ThirdStats);
if (!bHasAnyStats)
{
return FString::Printf(TEXT("%s none yet"), LaneLabel);
}
const float SuccessRate = TotalCompletedAttemptCount > 0
? static_cast<float>(TotalSuccessCount)
/ static_cast<float>(TotalCompletedAttemptCount)
: 0.0f;
const float AverageMistakes = OutcomeRunCount > 0
? static_cast<float>(
MistakeAccumulator / static_cast<double>(OutcomeRunCount))
: 0.0f;
return FString::Printf(
TEXT("%s launches %d | outcomes %d | success %.2f | avg mistakes %.2f"),
LaneLabel,
LaunchCount,
OutcomeRunCount,
SuccessRate,
AverageMistakes
);
};
int32 ComparablePeerOutcomeRuns = 0;
int32 SplitConfidenceOutcomeRuns = 0;
int32 PeerNoEvidenceOutcomeRuns = 0;
float ComparablePeerOutcomeShare = 0.0f;
const bool bGuardEarned = HasTemplateLaunchComparablePeerEvidenceForConfidenceBonus(
TemplateStats,
&ComparablePeerOutcomeRuns,
&SplitConfidenceOutcomeRuns,
&ComparablePeerOutcomeShare,
&PeerNoEvidenceOutcomeRuns
);
return FString::Printf(
TEXT("%s | %s | guard %s comparable-peer %d/%d outcomes share %.2f | peer-no-evidence %d"),
*BuildCombinedLaneSummary(
TEXT("comparable-peer-backed"),
&PeerWeakerStats,
&PeerMarginalStats,
&PeerClearedStats),
*BuildCombinedLaneSummary(
TEXT("peer-no-evidence-heavy"),
&PeerNoEvidenceStats,
nullptr,
nullptr),
bGuardEarned ? TEXT("earned") : TEXT("suppressed"),
ComparablePeerOutcomeRuns,
SplitConfidenceOutcomeRuns,
ComparablePeerOutcomeShare,
PeerNoEvidenceOutcomeRuns
);
}
FString BuildTemplateLaunchSelectionAnalyticsSupportDetailFragment(
const FHyperTwistTrainingTemplateLaunchSelectionProvenance* SelectionProvenance
)

View file

@ -0,0 +1,67 @@
# HyperTwist Phase 4 template launch comparable-peer confidence lanes packet
Created on `2026-05-07`
Status:
- first-party HyperTwist packet
- bounded Phase `4` dashboard analytics visibility slice
## Purpose
This packet surfaces the comparable-peer confidence guard result directly in shared template analytics detail by collapsing selector-split-confidence history into two operator-facing lanes:
- `comparable-peer-backed`
- `peer-no-evidence-heavy`
That makes it obvious whether confidence reinforcement is currently earned on peers with comparable support-kind evidence or suppressed because the template leans too heavily on empty peer lanes.
## Scope
Bounded lane:
- keep the existing raw peer support split
- synthesize two shared analytics lanes from the repo-backed peer disposition buckets
- append guard-earned / guard-suppressed status plus comparable-peer count/share to the shared template analytics detail
- let preferred template launch, template launch history, and template-backed recap inherit that visibility automatically
Out of scope:
- changing selector scoring again
- widening repository schema
- adding a dedicated dashboard panel
- changing persisted provenance
## What landed
Primary code changes:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp`
- added a shared formatter that combines peer-weaker, peer-marginal, and peer-cleared buckets into a `comparable-peer-backed` lane
- keeps the `peer-no-evidence-heavy` lane separate from the peer-no-evidence bucket
- reports whether the comparable-peer guard is currently earned or suppressed, along with comparable-peer outcome count/share and peer-no-evidence outcome count
- appends that synthesized confidence-lane view to the existing shared template analytics detail
## Product effect
Operators now get a quick confidence readout anywhere shared template analytics are shown:
- live `[Template Launch]` detail shows whether selector-split confidence is currently earned on comparable-peer-backed history
- template launch history shows the same lane split for the selected history row's template
- template-backed recap shows the same lane split for the displayed run's template
## Acceptance criteria
- shared template analytics detail shows `comparable-peer-backed` and `peer-no-evidence-heavy` confidence lanes
- shared detail shows guard-earned / guard-suppressed state with comparable-peer count/share
- live launch detail, template history, and recap all inherit the new lane split through the shared analytics fragment
- full product build succeeds
## Validation checklist
1. build `UnrealHyperTwist.sln` / `UnrealHyperTwistEditor`
2. confirm shared template analytics detail includes both confidence lanes
3. confirm shared detail shows guard-earned / guard-suppressed state with comparable-peer outcome count/share
4. confirm preferred template launch, template history, and recap all inherit the synthesized confidence lanes
That is the packet.