Persist template-signal support-bias snapshot

This commit is contained in:
axiomlogicnexus 2026-05-07 03:36:18 +02:00
parent 78d5057205
commit a46404dda6
3 changed files with 166 additions and 8 deletions

View file

@ -138,6 +138,11 @@ namespace HyperTwistCoachDashboardWidgetInternal
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot
BuildTemplateLaunchTemplateSignalSupportBiasSnapshot(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
);
FString BuildTemplateLaunchComparablePeerConfidenceAuditClause(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
const TCHAR* SubjectLabel
@ -156,6 +161,10 @@ namespace HyperTwistCoachDashboardWidgetInternal
const FHyperTwistTrainingTemplateLaunchSelectionProvenance* SelectionProvenance
);
FString BuildTemplateLaunchSelectionTemplateSignalSupportBiasDetailFragment(
const FHyperTwistTrainingTemplateLaunchSelectionProvenance* SelectionProvenance
);
bool HasTemplateLaunchComparablePeerEvidenceForConfidenceBonus(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats,
int32* OutComparablePeerOutcomeRuns = nullptr,
@ -369,7 +378,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
const FHyperTwistTrainingSessionTemplate& PeerTemplate,
const FHyperTwistTrainingTemplateLaunchScopedStats* PeerStats,
const EHyperTwistTrainingTemplateLaunchSelectionAnalyticsSupportKind AnalyticsSupportKind,
const bool bUsedTemplateSignalConfidenceSnapshotBias = false
const bool bUsedTemplateSignalSupportBias = false
)
{
FHyperTwistTrainingTemplateLaunchSelectionProvenance Provenance;
@ -417,21 +426,23 @@ namespace HyperTwistCoachDashboardWidgetInternal
}
else
{
Provenance.TemplateSignalSupportKind = bUsedTemplateSignalConfidenceSnapshotBias
Provenance.TemplateSignalSupportKind = bUsedTemplateSignalSupportBias
? EHyperTwistTrainingTemplateLaunchSelectionTemplateSignalSupportKind::
ConfidenceLaneBias
: EHyperTwistTrainingTemplateLaunchSelectionTemplateSignalSupportKind::
BroaderOutcomeOnly;
Provenance.TemplateSignalSupportBiasSnapshot =
BuildTemplateLaunchTemplateSignalSupportBiasSnapshot(SelectedStats);
Provenance.ComparablePeerConfidenceSnapshot =
BuildTemplateLaunchComparablePeerConfidenceSnapshot(SelectedStats);
const FString SelectedComparablePeerConfidenceAuditClause =
BuildTemplateLaunchComparablePeerConfidenceAuditClause(
SelectedStats,
TEXT("chosen template"));
if (bUsedTemplateSignalConfidenceSnapshotBias)
if (bUsedTemplateSignalSupportBias)
{
Provenance.DecisionSummaryLine = FString::Printf(
TEXT("Selector: tied with %s on primary dashboard priority; analytics preferred %s on broader template-scoped outcome signal with retained confidence-lane bias support: %s | chosen %s | peer %s."),
TEXT("Selector: tied with %s on primary dashboard priority; analytics preferred %s on broader template-scoped outcome signal with retained confidence-lane support-bias reinforcement: %s | chosen %s | peer %s."),
*ResolveDashboardTemplateLaunchDisplayTitle(PeerTemplate),
*ResolveDashboardTemplateLaunchDisplayTitle(SelectedTemplate),
*SelectedComparablePeerConfidenceAuditClause,
@ -442,7 +453,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
else
{
Provenance.DecisionSummaryLine = FString::Printf(
TEXT("Selector: tied with %s on primary dashboard priority; analytics preferred %s on broader template-scoped outcome signal without selector-split confidence support or retained confidence-lane bias support: %s | chosen %s | peer %s."),
TEXT("Selector: tied with %s on primary dashboard priority; analytics preferred %s on broader template-scoped outcome signal without support-bias reinforcement deciding the winner: %s | chosen %s | peer %s."),
*ResolveDashboardTemplateLaunchDisplayTitle(PeerTemplate),
*ResolveDashboardTemplateLaunchDisplayTitle(SelectedTemplate),
*SelectedComparablePeerConfidenceAuditClause,
@ -955,6 +966,23 @@ namespace HyperTwistCoachDashboardWidgetInternal
return Snapshot;
}
FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot
BuildTemplateLaunchTemplateSignalSupportBiasSnapshot(
const FHyperTwistTrainingTemplateLaunchScopedStats* TemplateStats
)
{
FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot Snapshot;
const bool bBiasEarned = HasTemplateLaunchTemplateSignalSupportBias(
TemplateStats,
&Snapshot.ConfidenceLaneBiasOutcomeRuns,
&Snapshot.BroaderOutcomeOnlyOutcomeRuns
);
Snapshot.State = bBiasEarned
? EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::Earned
: EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::Suppressed;
return Snapshot;
}
FString BuildTemplateLaunchComparablePeerConfidenceStatusClauseFromSnapshot(
const FHyperTwistTrainingTemplateLaunchComparablePeerConfidenceSnapshot& Snapshot
)
@ -1076,6 +1104,46 @@ namespace HyperTwistCoachDashboardWidgetInternal
);
}
FString BuildTemplateLaunchSelectionTemplateSignalSupportBiasDetailFragment(
const FHyperTwistTrainingTemplateLaunchSelectionProvenance* SelectionProvenance
)
{
if (SelectionProvenance == nullptr
|| SelectionProvenance->ReasonClass
!= EHyperTwistTrainingTemplateLaunchSelectionReasonClass::AnalyticsTieBreak
|| SelectionProvenance->AnalyticsSupportKind
!= EHyperTwistTrainingTemplateLaunchSelectionAnalyticsSupportKind::
TemplateScopedOutcomeSignal
|| !SelectionProvenance->TemplateSignalSupportBiasSnapshot.IsStructurallyValid())
{
return FString();
}
const FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot& Snapshot =
SelectionProvenance->TemplateSignalSupportBiasSnapshot;
switch (Snapshot.State)
{
case EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::Earned:
return FString::Printf(
TEXT(
" | at-launch support-bias earned on confidence-lane-bias history (%d bias outcomes vs %d broader outcomes)"),
Snapshot.ConfidenceLaneBiasOutcomeRuns,
Snapshot.BroaderOutcomeOnlyOutcomeRuns
);
case EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::
Suppressed:
return FString::Printf(
TEXT(
" | at-launch support-bias suppressed (%d bias outcomes vs %d broader outcomes)"),
Snapshot.ConfidenceLaneBiasOutcomeRuns,
Snapshot.BroaderOutcomeOnlyOutcomeRuns
);
case EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::None:
default:
return FString();
}
}
FString BuildTemplateLaunchSelectionComparablePeerConfidenceDetailFragment(
const FHyperTwistTrainingTemplateLaunchSelectionProvenance* SelectionProvenance
)
@ -1142,6 +1210,9 @@ namespace HyperTwistCoachDashboardWidgetInternal
const FString TemplateSignalSupportDetailFragment =
BuildTemplateLaunchSelectionTemplateSignalSupportDetailFragment(
SelectionProvenance);
const FString TemplateSignalSupportBiasDetailFragment =
BuildTemplateLaunchSelectionTemplateSignalSupportBiasDetailFragment(
SelectionProvenance);
const FString PeerSupportDispositionDetailFragment =
BuildTemplateLaunchSelectionPeerSupportDispositionDetailFragment(SelectionProvenance);
const FString ComparablePeerConfidenceDetailFragment =
@ -1149,6 +1220,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
SelectionProvenance);
const FString SelectionReasonDetailFragment =
AnalyticsSupportDetailFragment + TemplateSignalSupportDetailFragment
+ TemplateSignalSupportBiasDetailFragment
+ PeerSupportDispositionDetailFragment
+ ComparablePeerConfidenceDetailFragment;
if (!SelectionProvenance->PeerTemplateTitle.IsEmpty()
@ -2029,7 +2101,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
bool bPreferCandidate = false;
EHyperTwistTrainingTemplateLaunchSelectionAnalyticsSupportKind CandidateAnalyticsSupportKind =
EHyperTwistTrainingTemplateLaunchSelectionAnalyticsSupportKind::None;
bool bCandidateUsedTemplateSignalConfidenceSnapshotBias = false;
bool bCandidateUsedTemplateSignalSupportBias = false;
};
FTemplateLaunchAnalyticsPreferenceDecision ResolveTemplateAnalyticsPreferenceDecision(
@ -2082,7 +2154,7 @@ namespace HyperTwistCoachDashboardWidgetInternal
Decision.CandidateAnalyticsSupportKind =
EHyperTwistTrainingTemplateLaunchSelectionAnalyticsSupportKind::
TemplateScopedOutcomeSignal;
Decision.bCandidateUsedTemplateSignalConfidenceSnapshotBias = true;
Decision.bCandidateUsedTemplateSignalSupportBias = true;
}
return Decision;
}
@ -8835,7 +8907,7 @@ const FHyperTwistTrainingSessionTemplate* UHyperTwistCoachDashboardWidget::FindP
PreviousPreferredTemplate,
PreferredStats,
AnalyticsDecision.CandidateAnalyticsSupportKind,
AnalyticsDecision.bCandidateUsedTemplateSignalConfidenceSnapshotBias
AnalyticsDecision.bCandidateUsedTemplateSignalSupportBias
);
}
}

View file

@ -1082,6 +1082,14 @@ enum class EHyperTwistTrainingTemplateLaunchSelectionTemplateSignalSupportKind :
ConfidenceLaneBias UMETA(DisplayName = "Confidence Lane Bias")
};
UENUM(BlueprintType)
enum class EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState : uint8
{
None UMETA(DisplayName = "None"),
Earned UMETA(DisplayName = "Earned"),
Suppressed UMETA(DisplayName = "Suppressed")
};
UENUM(BlueprintType)
enum class EHyperTwistTrainingTemplateLaunchComparablePeerConfidenceSnapshotState : uint8
{
@ -1092,6 +1100,27 @@ enum class EHyperTwistTrainingTemplateLaunchComparablePeerConfidenceSnapshotStat
SuppressedPeerNoEvidenceHeavy UMETA(DisplayName = "Suppressed Peer No Evidence Heavy")
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState State =
EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::None;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ConfidenceLaneBiasOutcomeRuns = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 BroaderOutcomeOnlyOutcomeRuns = 0;
bool IsStructurallyValid() const
{
return State != EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState::None;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistTrainingTemplateLaunchComparablePeerConfidenceSnapshot
{
@ -1145,6 +1174,10 @@ struct FHyperTwistTrainingTemplateLaunchSelectionProvenance
TemplateSignalSupportKind =
EHyperTwistTrainingTemplateLaunchSelectionTemplateSignalSupportKind::None;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot
TemplateSignalSupportBiasSnapshot;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistTrainingTemplateLaunchComparablePeerConfidenceSnapshot
ComparablePeerConfidenceSnapshot;

View file

@ -0,0 +1,53 @@
# HyperTwist Phase 4 template-signal support-bias snapshot provenance packet
## Purpose
This packet persists the broader template-signal `support-bias earned/suppressed` state into template selection provenance at launch time. That keeps later audits honest: template history, recap, and other selector-detail surfaces now read the stored at-launch support-bias posture instead of inferring it from later analytics drift.
## Scope
- add a compact template-signal support-bias snapshot under template selection provenance
- capture:
- whether support-bias was `earned` or `suppressed` at launch
- the chosen template's retained `confidence-lane-bias` outcome count
- the chosen template's retained `broader-outcome-only` outcome count
- stamp that snapshot whenever the dashboard records a broader `TemplateScopedOutcomeSignal` analytics tie-break launch
- append the stored `at-launch support-bias` fragment through the shared selector-detail formatter used by live detail, template history, and recap
- correct broader-outcome decision-summary wording so it no longer claims the chosen template lacked retained support-bias when that bias simply did not decide the winner
## What landed
- `HyperTwistTrainingTypes.h`
- added `EHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshotState`
- added `FHyperTwistTrainingTemplateLaunchTemplateSignalSupportBiasSnapshot`
- nested `TemplateSignalSupportBiasSnapshot` under `FHyperTwistTrainingTemplateLaunchSelectionProvenance`
- `HyperTwistCoachDashboardWidget.cpp`
- added `BuildTemplateLaunchTemplateSignalSupportBiasSnapshot(...)`
- broader analytics provenance now stamps the selected template's support-bias snapshot at launch
- added shared selector-detail rendering for:
- `at-launch support-bias earned`
- `at-launch support-bias suppressed`
- renamed the local broader-analytics decision flag from the stale confidence-snapshot name to the actual support-bias meaning
- broader-outcome decision-summary text now says the winner launched without support-bias reinforcement deciding the outcome, rather than claiming the chosen template lacked retained support-bias entirely
## Product effect
- template history and recap now preserve the dashboard's at-launch support-bias posture for broader analytics launches
- selector-detail audits can distinguish:
- what kind of broader template-signal support actually decided the winner
- versus whether support-bias was merely present or suppressed at launch
- stored decision summaries no longer overstate the absence of retained support-bias when it existed but did not change the winner
## Acceptance criteria
- broader `TemplateScopedOutcomeSignal` launch provenance persists an `earned/suppressed` support-bias snapshot with both retained outcome counts
- shared selector detail shows the stored at-launch support-bias fragment in live detail, template history, and recap
- older runs without the new snapshot keep rendering without fabricated support-bias detail
- broader-outcome decision summaries avoid claiming the chosen template lacked retained support-bias when that state was simply non-decisive
## Validation checklist
1. full `Development Editor|Win64` build succeeds
2. confirm broader analytics provenance stamps `TemplateSignalSupportBiasSnapshot`
3. confirm shared selector detail renders stored `at-launch support-bias earned/suppressed`
4. confirm broader-outcome decision summaries use the corrected non-decisive wording