Guard template decision bias by selection split

This commit is contained in:
axiomlogicnexus 2026-05-07 15:20:57 +02:00
parent 2300045f63
commit 06b88284e9
2 changed files with 91 additions and 46 deletions

View file

@ -203,8 +203,8 @@ namespace HyperTwistCoachDashboardWidgetInternal
bool HasTemplateLaunchTemplateSignalSupportDecisionBias(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutSnapshotGuardOutcomeRuns = nullptr,
int32* OutNoSnapshotGuardOutcomeRuns = nullptr
int32* OutDecisionSplitGuardOutcomeRuns = nullptr,
int32* OutPlainSnapshotGuardOutcomeRuns = nullptr
);
int32 BuildTemplateLaunchAnalyticsTieBreakConfidenceBonus(
@ -854,18 +854,18 @@ namespace HyperTwistCoachDashboardWidgetInternal
- NoSnapshotGuardStats.AverageMistakesPerOutcomeRun
);
}
int32 SnapshotGuardOutcomeRuns = 0;
int32 NoSnapshotGuardOutcomeRuns = 0;
int32 DecisionSplitGuardOutcomeRuns = 0;
int32 PlainSnapshotGuardOutcomeRuns = 0;
const bool bDecisionBiasEarned = HasTemplateLaunchTemplateSignalSupportDecisionBias(
TemplateStats,
&SnapshotGuardOutcomeRuns,
&NoSnapshotGuardOutcomeRuns
&DecisionSplitGuardOutcomeRuns,
&PlainSnapshotGuardOutcomeRuns
);
Fragment += FString::Printf(
TEXT(" | decision-bias %s guard outcomes %d | no-guard outcomes %d"),
TEXT(" | decision-bias %s reinforced outcomes %d | plain outcomes %d"),
bDecisionBiasEarned ? TEXT("earned") : TEXT("suppressed"),
SnapshotGuardOutcomeRuns,
NoSnapshotGuardOutcomeRuns
DecisionSplitGuardOutcomeRuns,
PlainSnapshotGuardOutcomeRuns
);
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& PlainSnapshotGuardStats =
TemplateStats
@ -1877,10 +1877,10 @@ namespace HyperTwistCoachDashboardWidgetInternal
constexpr float TemplateLaunchTemplateSignalSupportBiasSnapshotMinimumSuccessDelta = 0.05f;
constexpr float TemplateLaunchTemplateSignalSupportBiasSnapshotMinimumMistakeImprovement =
0.5f;
constexpr int32 TemplateLaunchTemplateSignalSupportDecisionMinimumSnapshotGuardOutcomeRuns =
2;
constexpr int32 TemplateLaunchTemplateSignalSupportDecisionMinimumNoSnapshotGuardOutcomeRuns =
2;
constexpr int32
TemplateLaunchTemplateSignalSupportDecisionMinimumDecisionSplitGuardOutcomeRuns = 2;
constexpr int32
TemplateLaunchTemplateSignalSupportDecisionMinimumPlainSnapshotGuardOutcomeRuns = 2;
constexpr int32 TemplateLaunchTemplateSignalSupportDecisionMinimumScoreDelta = 1;
constexpr float TemplateLaunchTemplateSignalSupportDecisionMinimumSuccessDelta = 0.05f;
constexpr float TemplateLaunchTemplateSignalSupportDecisionMinimumMistakeImprovement = 0.5f;
@ -2289,63 +2289,67 @@ namespace HyperTwistCoachDashboardWidgetInternal
bool HasTemplateLaunchTemplateSignalSupportDecisionBias(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutSnapshotGuardOutcomeRuns,
int32* OutNoSnapshotGuardOutcomeRuns
int32* OutDecisionSplitGuardOutcomeRuns,
int32* OutPlainSnapshotGuardOutcomeRuns
)
{
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* SnapshotGuardStats = nullptr;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* NoSnapshotGuardStats =
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* DecisionSplitGuardStats =
nullptr;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats* PlainSnapshotGuardStats =
nullptr;
if (TemplateStats != nullptr && TemplateStats->IsStructurallyValid())
{
SnapshotGuardStats =
DecisionSplitGuardStats =
&TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotGuardStats;
NoSnapshotGuardStats =
->DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotGuardDecisionSplitGuardStats;
PlainSnapshotGuardStats =
&TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalNoSupportBiasSnapshotGuardStats;
->DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotGuardNoDecisionBiasStats;
}
const int32 SnapshotGuardOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(SnapshotGuardStats);
const int32 NoSnapshotGuardOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(NoSnapshotGuardStats);
if (OutSnapshotGuardOutcomeRuns != nullptr)
const int32 DecisionSplitGuardOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(DecisionSplitGuardStats);
const int32 PlainSnapshotGuardOutcomeRuns =
CountTemplateLaunchSelectionOutcomeRuns(PlainSnapshotGuardStats);
if (OutDecisionSplitGuardOutcomeRuns != nullptr)
{
*OutSnapshotGuardOutcomeRuns = SnapshotGuardOutcomeRuns;
*OutDecisionSplitGuardOutcomeRuns = DecisionSplitGuardOutcomeRuns;
}
if (OutNoSnapshotGuardOutcomeRuns != nullptr)
if (OutPlainSnapshotGuardOutcomeRuns != nullptr)
{
*OutNoSnapshotGuardOutcomeRuns = NoSnapshotGuardOutcomeRuns;
*OutPlainSnapshotGuardOutcomeRuns = PlainSnapshotGuardOutcomeRuns;
}
if (!HasTemplateLaunchTemplateSignalSupportBiasSnapshotBias(TemplateStats)
|| SnapshotGuardOutcomeRuns
< TemplateLaunchTemplateSignalSupportDecisionMinimumSnapshotGuardOutcomeRuns
|| NoSnapshotGuardOutcomeRuns
< TemplateLaunchTemplateSignalSupportDecisionMinimumNoSnapshotGuardOutcomeRuns)
|| DecisionSplitGuardOutcomeRuns
< TemplateLaunchTemplateSignalSupportDecisionMinimumDecisionSplitGuardOutcomeRuns
|| PlainSnapshotGuardOutcomeRuns
< TemplateLaunchTemplateSignalSupportDecisionMinimumPlainSnapshotGuardOutcomeRuns)
{
return false;
}
const int32 SnapshotGuardScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(SnapshotGuardStats);
const int32 NoSnapshotGuardScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(NoSnapshotGuardStats);
const int32 ScoreDelta = SnapshotGuardScore - NoSnapshotGuardScore;
const int32 DecisionSplitGuardScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(DecisionSplitGuardStats);
const int32 PlainSnapshotGuardScore =
BuildTemplateLaunchSelectionLaneAnalyticsScore(PlainSnapshotGuardStats);
const int32 ScoreDelta = DecisionSplitGuardScore - PlainSnapshotGuardScore;
const float SuccessDelta =
(SnapshotGuardStats != nullptr && SnapshotGuardStats->IsStructurallyValid()
? SnapshotGuardStats->OverallSuccessRate
(DecisionSplitGuardStats != nullptr && DecisionSplitGuardStats->IsStructurallyValid()
? DecisionSplitGuardStats->OverallSuccessRate
: 0.0f)
- (NoSnapshotGuardStats != nullptr && NoSnapshotGuardStats->IsStructurallyValid()
? NoSnapshotGuardStats->OverallSuccessRate
- (PlainSnapshotGuardStats != nullptr
&& PlainSnapshotGuardStats->IsStructurallyValid()
? PlainSnapshotGuardStats->OverallSuccessRate
: 0.0f);
const float MistakeImprovement =
(NoSnapshotGuardStats != nullptr && NoSnapshotGuardStats->IsStructurallyValid()
? NoSnapshotGuardStats->AverageMistakesPerOutcomeRun
(PlainSnapshotGuardStats != nullptr
&& PlainSnapshotGuardStats->IsStructurallyValid()
? PlainSnapshotGuardStats->AverageMistakesPerOutcomeRun
: 0.0f)
- (SnapshotGuardStats != nullptr && SnapshotGuardStats->IsStructurallyValid()
? SnapshotGuardStats->AverageMistakesPerOutcomeRun
- (DecisionSplitGuardStats != nullptr
&& DecisionSplitGuardStats->IsStructurallyValid()
? DecisionSplitGuardStats->AverageMistakesPerOutcomeRun
: 0.0f);
return ScoreDelta >= TemplateLaunchTemplateSignalSupportDecisionMinimumScoreDelta
|| SuccessDelta >= TemplateLaunchTemplateSignalSupportDecisionMinimumSuccessDelta

View file

@ -0,0 +1,41 @@
# HyperTwist Phase 4 template-signal decision-bias selection split guard packet
## Purpose
This packet tightens the stricter `DecisionSplitGuard` reinforcement rule so tied broader template-signal selection no longer compares that reinforced lane against all non-snapshot-guard history. It now compares reinforced `decision-split-guard` outcomes against plain snapshot-guard history, which is the actual lane the stricter guard is supposed to outperform before it gets extra preference.
## Scope
- retarget the existing template-signal decision-bias helper to compare:
- `decision-split-guard`
- vs `plain-snapshot-guard`
- keep the existing minimum-sample and score/success/mistake thresholds, but apply them to the new nested snapshot-guard split
- update shared analytics wording so the current decision-bias state reports reinforced and plain snapshot-guard outcome counts instead of broader guard vs no-guard counts
## What landed
- `HyperTwistCoachDashboardWidget.cpp`
- `HasTemplateLaunchTemplateSignalSupportDecisionBias(...)` now uses:
- `DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotGuardDecisionSplitGuardStats`
- `DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotGuardNoDecisionBiasStats`
- tied broader analytics selection still gates the stricter reinforcement through the same helper, but the helper now only earns when reinforced outcomes are actually beating plain snapshot-guard history
- shared `template-signal decision` analytics detail now reports:
- `decision-bias earned/suppressed reinforced outcomes ... | plain outcomes ...`
## Product effect
- the stricter `DecisionSplitGuard` lane now has to outperform plain snapshot-guard history, not merely broader no-snapshot-guard history, before it can reinforce future tied broader selections
- operators see the current gate in the same terms the selector now uses, which makes the analytics readout match the actual decision policy
## Acceptance criteria
- `HasTemplateLaunchTemplateSignalSupportDecisionBias(...)` compares reinforced `decision-split-guard` history against plain snapshot-guard history
- tied broader `TemplateScopedOutcomeSignal` selection only gets the stricter reinforcement when that reinforced-vs-plain comparison clears the existing thresholds
- shared analytics detail reports reinforced and plain snapshot-guard outcome counts for the current decision-bias state
## Validation checklist
1. full `Development Editor|Win64` build succeeds
2. confirm the decision-bias helper reads the nested snapshot-guard split instead of the older snapshot-guard vs no-snapshot-guard split
3. confirm shared analytics detail shows `decision-bias earned/suppressed reinforced outcomes ... | plain outcomes ...`
4. confirm tied broader analytics selection still flows through the same decision-bias helper after the comparison target change