Split template analytics by decision-bias snapshot

This commit is contained in:
axiomlogicnexus 2026-05-07 15:46:21 +02:00
parent dc93432f76
commit 2fdcaf46ee
4 changed files with 171 additions and 1 deletions

View file

@ -129,6 +129,10 @@ namespace HyperTwistCoachDashboardWidgetInternal
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
FString BuildTemplateLaunchAnalyticsTieBreakTemplateSignalDecisionBiasSnapshotFragment(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
FString BuildTemplateLaunchAnalyticsTieBreakTemplateSignalConfidenceSnapshotFragment(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
@ -240,7 +244,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 | template-signal support %s | template-signal decision %s | template-signal support-bias snapshot %s | template-signal confidence snapshot %s | peer support split %s | comparable-peer confidence %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 | template-signal support %s | template-signal decision %s | template-signal support-bias snapshot %s | template-signal decision-bias snapshot %s | template-signal confidence snapshot %s | peer support split %s | comparable-peer confidence %s | last launch %s | last completed %s"),
TemplateStats->AverageRecommendedCaseCount,
TemplateStats->AverageFocusCaseCount,
TemplateStats->AverageCompletedAttemptCount,
@ -259,6 +263,8 @@ namespace HyperTwistCoachDashboardWidgetInternal
TemplateStats),
*BuildTemplateLaunchAnalyticsTieBreakTemplateSignalSupportBiasSnapshotFragment(
TemplateStats),
*BuildTemplateLaunchAnalyticsTieBreakTemplateSignalDecisionBiasSnapshotFragment(
TemplateStats),
*BuildTemplateLaunchAnalyticsTieBreakTemplateSignalConfidenceSnapshotFragment(
TemplateStats),
*BuildTemplateLaunchAnalyticsTieBreakPeerDispositionSplitFragment(TemplateStats),
@ -977,6 +983,57 @@ namespace HyperTwistCoachDashboardWidgetInternal
return Fragment;
}
FString BuildTemplateLaunchAnalyticsTieBreakTemplateSignalDecisionBiasSnapshotFragment(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
)
{
if (TemplateStats == nullptr || !TemplateStats->IsStructurallyValid())
{
return TEXT(
"no template-signal decision-bias snapshot split is available for this template id yet");
}
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& EarnedStats =
TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedStats;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& SuppressedStats =
TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedStats;
const FHyperTwistTrainingTemplateLaunchSelectionScopedStats& NoRetainedStats =
TemplateStats
->DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedStats;
if (!EarnedStats.IsStructurallyValid()
&& !SuppressedStats.IsStructurallyValid()
&& !NoRetainedStats.IsStructurallyValid())
{
return TEXT(
"no template-signal decision-bias snapshot split is available for this template id yet");
}
FString Fragment = FString::Printf(
TEXT("%s | %s | %s"),
*BuildTemplateLaunchSelectionLaneAnalyticsSummary(EarnedStats, TEXT("earned")),
*BuildTemplateLaunchSelectionLaneAnalyticsSummary(SuppressedStats, TEXT("suppressed")),
*BuildTemplateLaunchSelectionLaneAnalyticsSummary(
NoRetainedStats,
TEXT("no-retained"))
);
if (EarnedStats.IsStructurallyValid()
&& SuppressedStats.IsStructurallyValid()
&& EarnedStats.GetOutcomeRunCount() > 0
&& SuppressedStats.GetOutcomeRunCount() > 0)
{
Fragment += FString::Printf(
TEXT(" | earned-minus-suppressed delta success %+.2f | delta mistakes %+.2f"),
EarnedStats.OverallSuccessRate - SuppressedStats.OverallSuccessRate,
EarnedStats.AverageMistakesPerOutcomeRun
- SuppressedStats.AverageMistakesPerOutcomeRun
);
}
return Fragment;
}
FString BuildTemplateLaunchAnalyticsTieBreakPeerDispositionSplitFragment(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
)

View file

@ -9180,6 +9180,12 @@ UHyperTwistTrainingRepositoryLibrary::ListTemplateLaunchScopedStatsForUser(
DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotSuppressedAccumulator;
FSelectionScopedAccumulator
DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotNoRetainedAccumulator;
FSelectionScopedAccumulator
DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedAccumulator;
FSelectionScopedAccumulator
DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedAccumulator;
FSelectionScopedAccumulator
DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedAccumulator;
FSelectionScopedAccumulator
DashboardAnalyticsTieBreakTemplateScopedSignalNoRetainedComparablePeerConfidenceLaneAccumulator;
FSelectionScopedAccumulator
@ -9433,6 +9439,38 @@ UHyperTwistTrainingRepositoryLibrary::ListTemplateLaunchScopedStatsForUser(
Provenance.SelectionProvenance
);
}
const EHyperTwistTrainingTemplateLaunchTemplateSignalSupportDecisionBiasSnapshotState
DecisionBiasSnapshotState =
Provenance.SelectionProvenance
.TemplateSignalSupportDecisionBiasSnapshot
.State;
if (DecisionBiasSnapshotState ==
EHyperTwistTrainingTemplateLaunchTemplateSignalSupportDecisionBiasSnapshotState::Earned)
{
AccumulateSelectionScopedStats(
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedAccumulator,
Provenance.SelectionProvenance
);
}
else if (
DecisionBiasSnapshotState ==
EHyperTwistTrainingTemplateLaunchTemplateSignalSupportDecisionBiasSnapshotState::Suppressed)
{
AccumulateSelectionScopedStats(
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedAccumulator,
Provenance.SelectionProvenance
);
}
else
{
AccumulateSelectionScopedStats(
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedAccumulator,
Provenance.SelectionProvenance
);
}
const EHyperTwistTrainingTemplateLaunchComparablePeerConfidenceSnapshotState
SnapshotState =
Provenance.SelectionProvenance.ComparablePeerConfidenceSnapshot.State;
@ -9771,6 +9809,21 @@ UHyperTwistTrainingRepositoryLibrary::ListTemplateLaunchScopedStatsForUser(
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotNoRetainedAccumulator
.Stats;
Accumulator.Stats
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedStats =
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedAccumulator
.Stats;
Accumulator.Stats
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedStats =
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedAccumulator
.Stats;
Accumulator.Stats
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedStats =
Accumulator
.DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedAccumulator
.Stats;
Accumulator.Stats
.DashboardAnalyticsTieBreakTemplateScopedSignalNoRetainedComparablePeerConfidenceLaneStats =
Accumulator

View file

@ -2388,6 +2388,18 @@ struct FHyperTwistTrainingTemplateLaunchScopedStats
FHyperTwistTrainingTemplateLaunchSelectionScopedStats
DashboardAnalyticsTieBreakTemplateScopedSignalSupportBiasSnapshotNoRetainedStats;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchSelectionScopedStats
DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedStats;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchSelectionScopedStats
DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedStats;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchSelectionScopedStats
DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedStats;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchSelectionScopedStats
DashboardAnalyticsTieBreakTemplateScopedSignalNoRetainedComparablePeerConfidenceLaneStats;

View file

@ -0,0 +1,48 @@
# HyperTwist Phase 4 template-signal decision-bias snapshot analytics packet
## Purpose
This packet pushes the newly persisted at-launch template-signal decision-bias snapshot into repo-backed template analytics. Broader `TemplateScopedOutcomeSignal` launches can now be compared by whether the reinforced-vs-plain snapshot-guard lane was already `earned`, still `suppressed`, or not retained yet at launch time.
## Scope
- widen per-template launch scoped stats with decision-bias snapshot buckets for:
- `earned`
- `suppressed`
- `no-retained`
- route broader template-signal dashboard analytics launches into those buckets from persisted selection provenance
- surface the new split through the shared dashboard analytics detail
## What landed
- `HyperTwistTrainingTypes.h`
- added repo-backed scoped stats for:
- `DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotEarnedStats`
- `DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotSuppressedStats`
- `DashboardAnalyticsTieBreakTemplateScopedSignalSupportDecisionBiasSnapshotNoRetainedStats`
- `HyperTwistTrainingRepositoryLibrary.cpp`
- widened the template launch scoped accumulator with matching decision-bias snapshot buckets
- routes broader `TemplateScopedOutcomeSignal` launches by persisted
`TemplateSignalSupportDecisionBiasSnapshot.State`
- treats older runs with no retained snapshot as `no-retained`
- `HyperTwistCoachDashboardWidget.cpp`
- added shared `template-signal decision-bias snapshot` analytics detail
- appends `earned-minus-suppressed` success and mistake deltas when both lanes have outcome history
## Product effect
- template analytics now show whether broader analytics picks launched with an already-earned reinforced-vs-plain guard are outperforming picks made while that lane was still suppressed
- history, recap, and live dashboard template analytics all inherit the same repo-backed split through the shared detail fragment
## Acceptance criteria
- repo-backed template analytics persist `earned`, `suppressed`, and `no-retained` buckets for at-launch decision-bias snapshot state
- broader `TemplateScopedOutcomeSignal` launches are routed by the stored snapshot state, not recomputed current guard state
- shared dashboard analytics detail shows the new `template-signal decision-bias snapshot` split
## Validation checklist
1. full `Development Editor|Win64` build succeeds
2. confirm repository analytics route broader template-signal launches by `TemplateSignalSupportDecisionBiasSnapshot.State`
3. confirm template scoped stats expose the three new decision-bias snapshot buckets
4. confirm shared analytics detail shows `template-signal decision-bias snapshot` with `earned`, `suppressed`, and `no-retained` lanes