Bias tied template analytics by confidence lane

This commit is contained in:
axiomlogicnexus 2026-05-07 03:08:08 +02:00
parent 961386af73
commit 3325dc40b9
2 changed files with 186 additions and 0 deletions

View file

@ -160,6 +160,14 @@ namespace HyperTwistCoachDashboardWidgetInternal
int32* OutPeerNoEvidenceOutcomeRuns = nullptr
);
bool HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutConfidenceEligibleOutcomeRuns = nullptr,
int32* OutTemplateSignalOutcomeRuns = nullptr,
float* OutConfidenceEligibleOutcomeShare = nullptr,
int32* OutSuppressedOutcomeRuns = nullptr
);
int32 BuildTemplateLaunchAnalyticsTieBreakConfidenceBonus(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
@ -570,6 +578,25 @@ namespace HyperTwistCoachDashboardWidgetInternal
NoRetainedLaneStats,
TEXT("no-retained-lane"))
);
int32 ConfidenceEligibleOutcomeRuns = 0;
int32 TemplateSignalOutcomeRuns = 0;
int32 SuppressedOutcomeRuns = 0;
float ConfidenceEligibleOutcomeShare = 0.0f;
const bool bBiasEarned = HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(
TemplateStats,
&ConfidenceEligibleOutcomeRuns,
&TemplateSignalOutcomeRuns,
&ConfidenceEligibleOutcomeShare,
&SuppressedOutcomeRuns
);
Fragment += FString::Printf(
TEXT(" | bias %s eligible %d/%d outcomes share %.2f | suppressed outcomes %d"),
bBiasEarned ? TEXT("earned") : TEXT("suppressed"),
ConfidenceEligibleOutcomeRuns,
TemplateSignalOutcomeRuns,
ConfidenceEligibleOutcomeShare,
SuppressedOutcomeRuns
);
if (ConfidenceEligibleStats.IsStructurallyValid()
&& SuppressedStats.IsStructurallyValid()
&& ConfidenceEligibleStats.GetOutcomeRunCount() > 0
@ -1335,6 +1362,11 @@ namespace HyperTwistCoachDashboardWidgetInternal
constexpr float TemplateLaunchSelectionTieBreakConfidenceMinimumMistakeImprovement = 0.5f;
constexpr int32 TemplateLaunchSelectionTieBreakConfidenceMinimumComparablePeerOutcomeRuns = 2;
constexpr float TemplateLaunchSelectionTieBreakConfidenceMinimumComparablePeerOutcomeShare = 0.40f;
constexpr int32 TemplateLaunchTemplateSignalConfidenceMinimumEligibleOutcomeRuns = 2;
constexpr float TemplateLaunchTemplateSignalConfidenceMinimumEligibleOutcomeShare = 0.50f;
constexpr int32 TemplateLaunchTemplateSignalConfidenceMinimumScoreDelta = 1;
constexpr float TemplateLaunchTemplateSignalConfidenceMinimumSuccessDelta = 0.05f;
constexpr float TemplateLaunchTemplateSignalConfidenceMinimumMistakeImprovement = 0.5f;
int32 CountTemplateLaunchOutcomeRuns(const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats)
{
@ -1479,6 +1511,95 @@ namespace HyperTwistCoachDashboardWidgetInternal
>= TemplateLaunchSelectionTieBreakConfidenceMinimumComparablePeerOutcomeShare;
}
bool HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutConfidenceEligibleOutcomeRuns,
int32* OutTemplateSignalOutcomeRuns,
float* OutConfidenceEligibleOutcomeShare,
int32* OutSuppressedOutcomeRuns
)
{
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* TemplateSignalStats = nullptr;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* ConfidenceEligibleStats =
nullptr;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* SuppressedStats = nullptr;
if (TemplateStats != nullptr && TemplateStats->IsStructurallyValid())
{
TemplateSignalStats =
&TemplateStats->DashboardAnalyticsTieBreakTemplateScopedSignalStats;
ConfidenceEligibleStats =
&TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalConfidenceEligibleStats;
SuppressedStats =
&TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalSuppressedPeerNoEvidenceHeavyStats;
}
const int32 ConfidenceEligibleOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(ConfidenceEligibleStats);
const int32 TemplateSignalOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(TemplateSignalStats);
const int32 SuppressedOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(SuppressedStats);
const float ConfidenceEligibleOutcomeShare = TemplateSignalOutcomeRuns > 0
? static_cast<float>(ConfidenceEligibleOutcomeRuns)
/ static_cast<float>(TemplateSignalOutcomeRuns)
: 0.0f;
if (OutConfidenceEligibleOutcomeRuns != nullptr)
{
*OutConfidenceEligibleOutcomeRuns = ConfidenceEligibleOutcomeRuns;
}
if (OutTemplateSignalOutcomeRuns != nullptr)
{
*OutTemplateSignalOutcomeRuns = TemplateSignalOutcomeRuns;
}
if (OutConfidenceEligibleOutcomeShare != nullptr)
{
*OutConfidenceEligibleOutcomeShare = ConfidenceEligibleOutcomeShare;
}
if (OutSuppressedOutcomeRuns != nullptr)
{
*OutSuppressedOutcomeRuns = SuppressedOutcomeRuns;
}
if (ConfidenceEligibleOutcomeRuns
< TemplateLaunchTemplateSignalConfidenceMinimumEligibleOutcomeRuns
|| ConfidenceEligibleOutcomeShare
< TemplateLaunchTemplateSignalConfidenceMinimumEligibleOutcomeShare)
{
return false;
}
if (SuppressedOutcomeRuns <= 0)
{
return true;
}
const int32 ConfidenceEligibleScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(ConfidenceEligibleStats);
const int32 SuppressedScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(SuppressedStats);
const int32 ScoreDelta = ConfidenceEligibleScore - SuppressedScore;
const float SuccessDelta =
(ConfidenceEligibleStats != nullptr && ConfidenceEligibleStats->IsStructurallyValid()
? ConfidenceEligibleStats->OverallSuccessRate
: 0.0f)
- (SuppressedStats != nullptr && SuppressedStats->IsStructurallyValid()
? SuppressedStats->OverallSuccessRate
: 0.0f);
const float MistakeImprovement =
(SuppressedStats != nullptr && SuppressedStats->IsStructurallyValid()
? SuppressedStats->AverageMistakesPerOutcomeRun
: 0.0f)
- (ConfidenceEligibleStats != nullptr && ConfidenceEligibleStats->IsStructurallyValid()
? ConfidenceEligibleStats->AverageMistakesPerOutcomeRun
: 0.0f);
return ScoreDelta >= TemplateLaunchTemplateSignalConfidenceMinimumScoreDelta
|| SuccessDelta >= TemplateLaunchTemplateSignalConfidenceMinimumSuccessDelta
|| MistakeImprovement
>= TemplateLaunchTemplateSignalConfidenceMinimumMistakeImprovement;
}
int32 BuildTemplateLaunchAnalyticsTieBreakConfidenceBonus(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
)
@ -1736,6 +1857,24 @@ namespace HyperTwistCoachDashboardWidgetInternal
}
return Decision;
}
const int32 CandidateTemplateSignalConfidenceSnapshotBonus =
HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(CandidateStats) ? 1 : 0;
const int32 IncumbentTemplateSignalConfidenceSnapshotBonus =
HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(IncumbentStats) ? 1 : 0;
if (CandidateTemplateSignalConfidenceSnapshotBonus
!= IncumbentTemplateSignalConfidenceSnapshotBonus)
{
Decision.bPreferCandidate =
CandidateTemplateSignalConfidenceSnapshotBonus
> IncumbentTemplateSignalConfidenceSnapshotBonus;
if (Decision.bPreferCandidate)
{
Decision.CandidateAnalyticsSupportKind =
EHyperTwistTrainingTemplateLaunchSelectionAnalyticsSupportKind::
TemplateScopedOutcomeSignal;
}
return Decision;
}
if (CandidateOutcomeRuns != IncumbentOutcomeRuns)
{
Decision.bPreferCandidate = CandidateOutcomeRuns > IncumbentOutcomeRuns;

View file

@ -0,0 +1,47 @@
# HyperTwist Phase 4 template-signal confidence scoring bias packet
## Purpose
This packet feeds the new broader `TemplateScopedOutcomeSignal` confidence-snapshot split back into actual dashboard analytics tie-break selection. When the existing analytics score already ties, the selector can now conservatively prefer a template whose broader analytics wins are already landing in the `confidence-eligible` lane instead of a competing template whose broader wins still cluster in the `suppressed` lane.
## Scope
- add a conservative template-signal confidence-snapshot bias helper in dashboard selection logic
- require minimum `confidence-eligible` outcome count and share before the bias can exist
- if the template still has suppressed broader-history outcomes, require the eligible lane to beat or clearly improve on the suppressed lane before the bias is awarded
- apply that bias only after the existing analytics score ties
- surface the same bias-earned / bias-suppressed state in shared template analytics detail
## What landed
- `HyperTwistCoachDashboardWidget.cpp`
- added `HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(...)`
- new guard requirements:
- at least `2` `confidence-eligible` outcome runs
- at least `0.50` eligible share within broader template-signal outcomes
- if suppressed broader-history exists, eligible outcomes must beat it on lane score or show meaningful success / mistake improvement
- `ResolveTemplateAnalyticsPreferenceDecision(...)` now consults this bias only after the existing analytics score already ties
- shared template analytics detail now appends:
- `bias earned` or `bias suppressed`
- eligible outcome count/share
- suppressed outcome count
## Product effect
- broader template-signal confidence history no longer just sits in analytics detail; it can now break otherwise tied analytics choices
- the bias stays conservative because it does not override the main analytics score and it requires both sample depth and lane-share support
- live `[Template Launch]` detail, template launch history, and run recap now expose whether the broader template-signal bias is currently earned or suppressed for the displayed template
## Acceptance criteria
- the new broader template-signal confidence bias only applies after the current analytics score ties
- the bias requires minimum eligible outcome count and share
- suppressed broader-history prevents the bias unless the eligible lane meaningfully beats or improves on it
- shared analytics detail shows whether the broader template-signal bias is earned or suppressed
## Validation checklist
1. full `Development Editor|Win64` build succeeds
2. confirm `ResolveTemplateAnalyticsPreferenceDecision(...)` checks the new bias only after score equality
3. confirm the bias requires minimum eligible outcome count/share
4. confirm shared analytics detail reports `bias earned` or `bias suppressed` with eligible count/share and suppressed count