Guard template-signal bias by support split

This commit is contained in:
axiomlogicnexus 2026-05-07 03:28:17 +02:00
parent 2f8f392b84
commit 78d5057205
2 changed files with 154 additions and 9 deletions

View file

@ -172,6 +172,12 @@ namespace HyperTwistCoachDashboardWidgetInternal
int32* OutSuppressedOutcomeRuns = nullptr
);
bool HasTemplateLaunchTemplateSignalSupportBias(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutConfidenceLaneBiasOutcomeRuns = nullptr,
int32* OutBroaderOutcomeOnlyOutcomeRuns = nullptr
);
int32 BuildTemplateLaunchAnalyticsTieBreakConfidenceBonus(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
@ -634,7 +640,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
&SuppressedOutcomeRuns
);
Fragment += FString::Printf(
TEXT(" | bias %s eligible %d/%d outcomes share %.2f | suppressed outcomes %d"),
TEXT(" | snapshot-bias %s eligible %d/%d outcomes share %.2f | suppressed outcomes %d"),
bBiasEarned ? TEXT("earned") : TEXT("suppressed"),
ConfidenceEligibleOutcomeRuns,
TemplateSignalOutcomeRuns,
@ -698,6 +704,19 @@ namespace HyperTwistCoachDashboardWidgetInternal
- BroaderOutcomeOnlyStats.AverageMistakesPerOutcomeRun
);
}
int32 ConfidenceLaneBiasOutcomeRuns = 0;
int32 BroaderOutcomeOnlyOutcomeRuns = 0;
const bool bSupportBiasEarned = HasTemplateLaunchTemplateSignalSupportBias(
TemplateStats,
&ConfidenceLaneBiasOutcomeRuns,
&BroaderOutcomeOnlyOutcomeRuns
);
Fragment += FString::Printf(
TEXT(" | support-bias %s bias outcomes %d | broader outcomes %d"),
bSupportBiasEarned ? TEXT("earned") : TEXT("suppressed"),
ConfidenceLaneBiasOutcomeRuns,
BroaderOutcomeOnlyOutcomeRuns
);
return Fragment;
}
@ -1483,6 +1502,13 @@ namespace HyperTwistCoachDashboardWidgetInternal
constexpr int32 TemplateLaunchTemplateSignalConfidenceMinimumScoreDelta = 1;
constexpr float TemplateLaunchTemplateSignalConfidenceMinimumSuccessDelta = 0.05f;
constexpr float TemplateLaunchTemplateSignalConfidenceMinimumMistakeImprovement = 0.5f;
constexpr int32 TemplateLaunchTemplateSignalSupportBiasMinimumConfidenceLaneBiasOutcomeRuns =
2;
constexpr int32 TemplateLaunchTemplateSignalSupportBiasMinimumBroaderOutcomeOnlyOutcomeRuns =
2;
constexpr int32 TemplateLaunchTemplateSignalSupportBiasMinimumScoreDelta = 1;
constexpr float TemplateLaunchTemplateSignalSupportBiasMinimumSuccessDelta = 0.05f;
constexpr float TemplateLaunchTemplateSignalSupportBiasMinimumMistakeImprovement = 0.5f;
int32 CountTemplateLaunchOutcomeRuns(const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats)
{
@ -1716,6 +1742,73 @@ namespace HyperTwistCoachDashboardWidgetInternal
>= TemplateLaunchTemplateSignalConfidenceMinimumMistakeImprovement;
}
bool HasTemplateLaunchTemplateSignalSupportBias(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutConfidenceLaneBiasOutcomeRuns,
int32* OutBroaderOutcomeOnlyOutcomeRuns
)
{
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* ConfidenceLaneBiasStats =
nullptr;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* BroaderOutcomeOnlyStats =
nullptr;
if (TemplateStats != nullptr && TemplateStats->IsStructurallyValid())
{
ConfidenceLaneBiasStats =
&TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalConfidenceLaneBiasStats;
BroaderOutcomeOnlyStats =
&TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalBroaderOutcomeOnlyStats;
}
const int32 ConfidenceLaneBiasOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(ConfidenceLaneBiasStats);
const int32 BroaderOutcomeOnlyOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(BroaderOutcomeOnlyStats);
if (OutConfidenceLaneBiasOutcomeRuns != nullptr)
{
*OutConfidenceLaneBiasOutcomeRuns = ConfidenceLaneBiasOutcomeRuns;
}
if (OutBroaderOutcomeOnlyOutcomeRuns != nullptr)
{
*OutBroaderOutcomeOnlyOutcomeRuns = BroaderOutcomeOnlyOutcomeRuns;
}
if (!HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(TemplateStats)
|| ConfidenceLaneBiasOutcomeRuns
< TemplateLaunchTemplateSignalSupportBiasMinimumConfidenceLaneBiasOutcomeRuns
|| BroaderOutcomeOnlyOutcomeRuns
< TemplateLaunchTemplateSignalSupportBiasMinimumBroaderOutcomeOnlyOutcomeRuns)
{
return false;
}
const int32 ConfidenceLaneBiasScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(ConfidenceLaneBiasStats);
const int32 BroaderOutcomeOnlyScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(BroaderOutcomeOnlyStats);
const int32 ScoreDelta = ConfidenceLaneBiasScore - BroaderOutcomeOnlyScore;
const float SuccessDelta =
(ConfidenceLaneBiasStats != nullptr && ConfidenceLaneBiasStats->IsStructurallyValid()
? ConfidenceLaneBiasStats->OverallSuccessRate
: 0.0f)
- (BroaderOutcomeOnlyStats != nullptr && BroaderOutcomeOnlyStats->IsStructurallyValid()
? BroaderOutcomeOnlyStats->OverallSuccessRate
: 0.0f);
const float MistakeImprovement =
(BroaderOutcomeOnlyStats != nullptr && BroaderOutcomeOnlyStats->IsStructurallyValid()
? BroaderOutcomeOnlyStats->AverageMistakesPerOutcomeRun
: 0.0f)
- (ConfidenceLaneBiasStats != nullptr && ConfidenceLaneBiasStats->IsStructurallyValid()
? ConfidenceLaneBiasStats->AverageMistakesPerOutcomeRun
: 0.0f);
return ScoreDelta >= TemplateLaunchTemplateSignalSupportBiasMinimumScoreDelta
|| SuccessDelta >= TemplateLaunchTemplateSignalSupportBiasMinimumSuccessDelta
|| MistakeImprovement
>= TemplateLaunchTemplateSignalSupportBiasMinimumMistakeImprovement;
}
int32 BuildTemplateLaunchAnalyticsTieBreakConfidenceBonus(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
)
@ -1974,16 +2067,16 @@ namespace HyperTwistCoachDashboardWidgetInternal
}
return Decision;
}
const int32 CandidateTemplateSignalConfidenceSnapshotBonus =
HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(CandidateStats) ? 1 : 0;
const int32 IncumbentTemplateSignalConfidenceSnapshotBonus =
HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(IncumbentStats) ? 1 : 0;
if (CandidateTemplateSignalConfidenceSnapshotBonus
!= IncumbentTemplateSignalConfidenceSnapshotBonus)
const int32 CandidateTemplateSignalSupportBiasBonus =
HasTemplateLaunchTemplateSignalSupportBias(CandidateStats) ? 1 : 0;
const int32 IncumbentTemplateSignalSupportBiasBonus =
HasTemplateLaunchTemplateSignalSupportBias(IncumbentStats) ? 1 : 0;
if (CandidateTemplateSignalSupportBiasBonus
!= IncumbentTemplateSignalSupportBiasBonus)
{
Decision.bPreferCandidate =
CandidateTemplateSignalConfidenceSnapshotBonus
> IncumbentTemplateSignalConfidenceSnapshotBonus;
CandidateTemplateSignalSupportBiasBonus
> IncumbentTemplateSignalSupportBiasBonus;
if (Decision.bPreferCandidate)
{
Decision.CandidateAnalyticsSupportKind =

View file

@ -0,0 +1,52 @@
# HyperTwist Phase 4 template-signal support bias guard packet
## Purpose
This packet feeds the new `broader-outcome-only` versus `confidence-lane-bias` support split back into tied dashboard analytics selection. A template no longer gets the extra broader template-signal bias just because its retained confidence-snapshot lane looks eligible; it now also needs enough stored `confidence-lane-bias` outcomes and those outcomes need to beat plain broader-outcome wins.
## Scope
- add a support-split guard helper for broader template-signal bias
- require the older confidence-snapshot bias to be earned first
- require minimum outcome history in both:
- `confidence-lane-bias`
- `broader-outcome-only`
- require the confidence-lane-bias bucket to beat the broader-outcome-only bucket on score or meaningful success / mistake improvement
- use that stricter helper in tied analytics selection
- surface the same `support-bias earned/suppressed` state in shared template analytics detail
## What landed
- `HyperTwistCoachDashboardWidget.cpp`
- added `HasTemplateLaunchTemplateSignalSupportBias(...)`
- the helper only returns true when:
- `HasTemplateLaunchTemplateSignalConfidenceSnapshotBias(...)` already clears
- the template has at least `2` confidence-lane-bias outcome runs
- the template has at least `2` broader-outcome-only outcome runs
- the confidence-lane-bias bucket beats broader-outcome-only on lane score or shows meaningful success / mistake improvement
- `ResolveTemplateAnalyticsPreferenceDecision(...)` now uses this stricter support bias when breaking otherwise tied broader analytics outcomes
- shared `template-signal support` analytics detail now appends:
- `support-bias earned`
- or `support-bias suppressed`
- plus the stored bias / broader outcome counts
- the older confidence-snapshot fragment now labels its state as `snapshot-bias` so the two guards are not conflated
## Product effect
- broader template-signal bias only reinforces future tied selections when stored confidence-lane-bias outcomes have enough depth and are outperforming plain broader-outcome wins
- templates with sparse or weaker confidence-lane-bias history no longer get that extra tie-break preference
- live `[Template Launch]` detail, template history, and recap now show both the snapshot-bias state and the stricter support-bias state
## Acceptance criteria
- tied analytics selection uses the stricter support bias instead of the older snapshot bias alone
- support bias requires minimum outcome history in both compared support buckets
- support bias only clears when confidence-lane-bias beats broader-outcome-only on score or meaningful quality deltas
- shared analytics detail exposes `support-bias earned/suppressed` with both bucket counts
## Validation checklist
1. full `Development Editor|Win64` build succeeds
2. confirm tied analytics selection now checks `HasTemplateLaunchTemplateSignalSupportBias(...)`
3. confirm the helper requires both bucket minimums and a positive lane comparison
4. confirm shared analytics detail shows both `snapshot-bias` and `support-bias`