Implement Phase 6R-AB provider usage cost history export shell

This commit is contained in:
axiomlogicnexus 2026-05-25 17:37:23 +02:00
parent a2fba2ef99
commit bb15b91682
14 changed files with 1627 additions and 28 deletions

View file

@ -962,6 +962,68 @@ namespace HyperTwistContractLibraryInternal
return Profile;
}
FHyperTwistSpeechUsageCostHistoryExportShellProfile
MakeDefaultSpeechUsageCostHistoryExportShellProfile(const FString& ProfileId)
{
FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile;
Profile.HistoryExportShellProfileId = ProfileId;
Profile.ShellKind = TEXT("operator-usage-cost-history-export");
Profile.HistorySurfaceMode = TEXT("rolling-usage-cost-snapshot-history");
Profile.ExportSurfaceMode = TEXT("first-party-summary-preview");
Profile.RefreshActionId = TEXT("refresh-provider-usage-cost-history");
Profile.ExportPreviewActionId = TEXT("preview-provider-usage-cost-export");
Profile.CopySummaryActionId = TEXT("copy-provider-usage-cost-summary");
Profile.RouteInspectActionId = TEXT("inspect-provider-route");
Profile.BudgetInspectActionId = TEXT("review-provider-budget");
Profile.RetainedHistoryEntryLimit = 12;
Profile.bSupportsHistoryTimeline = true;
Profile.bSupportsExportPreview = true;
Profile.bSupportsCopySummary = true;
Profile.bSupportsEstimateWatermark = true;
Profile.bPreservesFirstPartySummaryOwnership = true;
auto AddPanel = [&Profile](
const TCHAR* PanelId,
const TCHAR* PanelKind,
const TCHAR* AnchorId,
const bool bVisibleByDefault
)
{
FHyperTwistSpeechShellPanelLayout Panel;
Panel.PanelId = PanelId;
Panel.PanelKind = PanelKind;
Panel.AnchorId = AnchorId;
Panel.bVisibleByDefault = bVisibleByDefault;
Profile.Panels.Add(Panel);
};
auto AddAction = [&Profile](
const TCHAR* ActionId,
const TCHAR* InputBinding,
const TCHAR* SurfaceId
)
{
FHyperTwistSpeechShellActionBinding ActionBinding;
ActionBinding.ActionId = ActionId;
ActionBinding.InputBinding = InputBinding;
ActionBinding.SurfaceId = SurfaceId;
Profile.ActionBindings.Add(ActionBinding);
};
AddPanel(TEXT("history-timeline-card"), TEXT("history-timeline-card"), TEXT("top-left"), true);
AddPanel(TEXT("history-summary-card"), TEXT("history-summary-card"), TEXT("left-stack-below-history"), true);
AddPanel(TEXT("export-preview-card"), TEXT("export-preview-card"), TEXT("top-right"), true);
AddPanel(TEXT("export-readiness-card"), TEXT("export-readiness-card"), TEXT("right-stack-below-preview"), true);
AddAction(TEXT("refresh-provider-usage-cost-history"), TEXT("F6"), TEXT("history-timeline-card"));
AddAction(TEXT("preview-provider-usage-cost-export"), TEXT("E"), TEXT("export-preview-card"));
AddAction(TEXT("copy-provider-usage-cost-summary"), TEXT("C"), TEXT("export-readiness-card"));
AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("history-summary-card"));
AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("export-readiness-card"));
AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
return Profile;
}
FHyperTwistSpeechModelPayloadDescriptor MakeSpeechModelPayloadDescriptor(
const TCHAR* PayloadId,
const TCHAR* PayloadKind,
@ -1043,7 +1105,10 @@ namespace HyperTwistContractLibraryInternal
TEXT("quotaRateLimitState"),
TEXT("providerUsageCostDashboardShell"),
TEXT("providerQuotaEscalationBanner"),
TEXT("providerRouteCostDiagnostics")
TEXT("providerRouteCostDiagnostics"),
TEXT("providerUsageCostHistoryShell"),
TEXT("providerUsageCostExportPreview"),
TEXT("providerUsageCostSummaryCopy")
};
}
@ -2269,6 +2334,12 @@ FHyperTwistSpeechSessionConfig UHyperTwistContractLibrary::MakeSampleSpeechSessi
HyperTwistContractLibraryInternal::MakeDefaultSpeechUsageCostDashboardShellProfile(
Config.UsageCostDashboardShellProfileId
);
Config.UsageCostHistoryExportShellProfileId =
TEXT("speech-provider-usage-cost-history-export-shell-v1");
Config.UsageCostHistoryExportShellProfileDefinition =
HyperTwistContractLibraryInternal::MakeDefaultSpeechUsageCostHistoryExportShellProfile(
Config.UsageCostHistoryExportShellProfileId
);
Config.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1");
Config.PayloadCustodyProfileDefinition =
HyperTwistContractLibraryInternal::MakeDefaultSpeechPayloadCustodyProfile(
@ -2379,7 +2450,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistContractLibrary::MakeMockSpeechService
TEXT("quotaRateLimitState"),
TEXT("providerUsageCostDashboardShell"),
TEXT("providerQuotaEscalationBanner"),
TEXT("providerRouteCostDiagnostics")
TEXT("providerRouteCostDiagnostics"),
TEXT("providerUsageCostHistoryShell"),
TEXT("providerUsageCostExportPreview"),
TEXT("providerUsageCostSummaryCopy")
};
Health.SupportedOrchestrationProfiles = {
TEXT("python-batch-transcribe-v1")

View file

@ -344,7 +344,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal
TEXT("quotaRateLimitState"),
TEXT("providerUsageCostDashboardShell"),
TEXT("providerQuotaEscalationBanner"),
TEXT("providerRouteCostDiagnostics")
TEXT("providerRouteCostDiagnostics"),
TEXT("providerUsageCostHistoryShell"),
TEXT("providerUsageCostExportPreview"),
TEXT("providerUsageCostSummaryCopy")
};
Health.SupportedOrchestrationProfiles = {
TEXT("python-batch-transcribe-v1")
@ -421,7 +424,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal
TEXT("quotaRateLimitState"),
TEXT("providerUsageCostDashboardShell"),
TEXT("providerQuotaEscalationBanner"),
TEXT("providerRouteCostDiagnostics")
TEXT("providerRouteCostDiagnostics"),
TEXT("providerUsageCostHistoryShell"),
TEXT("providerUsageCostExportPreview"),
TEXT("providerUsageCostSummaryCopy")
};
Health.SupportedOrchestrationProfiles = {
TEXT("python-batch-transcribe-v1")
@ -483,6 +489,9 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal
Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostHistoryShell"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostExportPreview"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostSummaryCopy"));
Health.SupportedOrchestrationProfiles.AddUnique(TEXT("python-batch-transcribe-v1"));
if (Health.ProviderProfileId.IsEmpty())
{

View file

@ -149,6 +149,9 @@ FHyperTwistSpeechServiceHealth UHyperTwistMockSpeechClient::GetSpeechServiceHeal
Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostHistoryShell"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostExportPreview"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostSummaryCopy"));
Health.SupportedOrchestrationProfiles.AddUnique(TEXT("python-batch-transcribe-v1"));
return Health;
}

View file

@ -2921,6 +2921,11 @@ namespace HyperTwistTrainingSubsystemInternal
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
);
FHyperTwistSpeechUsageCostHistoryExportShellState BuildSpeechUsageCostHistoryExportShellState(
const FHyperTwistSpeechSessionConfig& SessionConfig,
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
);
FHyperTwistSpeechMicrophoneShellProfile BuildDefaultCoachCommandMicrophoneShellProfile(const FString& ProfileId)
{
FHyperTwistSpeechMicrophoneShellProfile Profile;
@ -3042,6 +3047,68 @@ namespace HyperTwistTrainingSubsystemInternal
return Profile;
}
FHyperTwistSpeechUsageCostHistoryExportShellProfile
BuildDefaultSpeechUsageCostHistoryExportShellProfile(const FString& ProfileId)
{
FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile;
Profile.HistoryExportShellProfileId = ProfileId;
Profile.ShellKind = TEXT("operator-usage-cost-history-export");
Profile.HistorySurfaceMode = TEXT("rolling-usage-cost-snapshot-history");
Profile.ExportSurfaceMode = TEXT("first-party-summary-preview");
Profile.RefreshActionId = TEXT("refresh-provider-usage-cost-history");
Profile.ExportPreviewActionId = TEXT("preview-provider-usage-cost-export");
Profile.CopySummaryActionId = TEXT("copy-provider-usage-cost-summary");
Profile.RouteInspectActionId = TEXT("inspect-provider-route");
Profile.BudgetInspectActionId = TEXT("review-provider-budget");
Profile.RetainedHistoryEntryLimit = 12;
Profile.bSupportsHistoryTimeline = true;
Profile.bSupportsExportPreview = true;
Profile.bSupportsCopySummary = true;
Profile.bSupportsEstimateWatermark = true;
Profile.bPreservesFirstPartySummaryOwnership = true;
auto AddPanel = [&Profile](
const TCHAR* PanelId,
const TCHAR* PanelKind,
const TCHAR* AnchorId,
const bool bVisibleByDefault
)
{
FHyperTwistSpeechShellPanelLayout Panel;
Panel.PanelId = PanelId;
Panel.PanelKind = PanelKind;
Panel.AnchorId = AnchorId;
Panel.bVisibleByDefault = bVisibleByDefault;
Profile.Panels.Add(Panel);
};
auto AddAction = [&Profile](
const TCHAR* ActionId,
const TCHAR* InputBinding,
const TCHAR* SurfaceId
)
{
FHyperTwistSpeechShellActionBinding ActionBinding;
ActionBinding.ActionId = ActionId;
ActionBinding.InputBinding = InputBinding;
ActionBinding.SurfaceId = SurfaceId;
Profile.ActionBindings.Add(ActionBinding);
};
AddPanel(TEXT("history-timeline-card"), TEXT("history-timeline-card"), TEXT("top-left"), true);
AddPanel(TEXT("history-summary-card"), TEXT("history-summary-card"), TEXT("left-stack-below-history"), true);
AddPanel(TEXT("export-preview-card"), TEXT("export-preview-card"), TEXT("top-right"), true);
AddPanel(TEXT("export-readiness-card"), TEXT("export-readiness-card"), TEXT("right-stack-below-preview"), true);
AddAction(TEXT("refresh-provider-usage-cost-history"), TEXT("F6"), TEXT("history-timeline-card"));
AddAction(TEXT("preview-provider-usage-cost-export"), TEXT("E"), TEXT("export-preview-card"));
AddAction(TEXT("copy-provider-usage-cost-summary"), TEXT("C"), TEXT("export-readiness-card"));
AddAction(TEXT("inspect-provider-route"), TEXT("P"), TEXT("history-summary-card"));
AddAction(TEXT("review-provider-budget"), TEXT("B"), TEXT("export-readiness-card"));
AddAction(TEXT("close-speech-session"), TEXT("Escape"), TEXT("session-root"));
return Profile;
}
FHyperTwistSpeechModelPayloadDescriptor MakeSpeechModelPayloadDescriptor(
const TCHAR* PayloadId,
const TCHAR* PayloadKind,
@ -3123,7 +3190,10 @@ namespace HyperTwistTrainingSubsystemInternal
TEXT("quotaRateLimitState"),
TEXT("providerUsageCostDashboardShell"),
TEXT("providerQuotaEscalationBanner"),
TEXT("providerRouteCostDiagnostics")
TEXT("providerRouteCostDiagnostics"),
TEXT("providerUsageCostHistoryShell"),
TEXT("providerUsageCostExportPreview"),
TEXT("providerUsageCostSummaryCopy")
};
}
@ -3778,6 +3848,26 @@ namespace HyperTwistTrainingSubsystemInternal
}
SessionConfig.UsageCostDashboardShellProfileId =
SessionConfig.UsageCostDashboardShellProfileDefinition.DashboardShellProfileId;
if (SessionConfig.UsageCostHistoryExportShellProfileId.IsEmpty()
&& SessionConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid())
{
SessionConfig.UsageCostHistoryExportShellProfileId =
SessionConfig.UsageCostHistoryExportShellProfileDefinition.HistoryExportShellProfileId;
}
if (SessionConfig.UsageCostHistoryExportShellProfileId.IsEmpty())
{
SessionConfig.UsageCostHistoryExportShellProfileId =
TEXT("speech-provider-usage-cost-history-export-shell-v1");
}
if (!SessionConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid())
{
SessionConfig.UsageCostHistoryExportShellProfileDefinition =
BuildDefaultSpeechUsageCostHistoryExportShellProfile(
SessionConfig.UsageCostHistoryExportShellProfileId
);
}
SessionConfig.UsageCostHistoryExportShellProfileId =
SessionConfig.UsageCostHistoryExportShellProfileDefinition.HistoryExportShellProfileId;
}
void ApplySpeechProviderProfileHealthDefaults(
@ -4110,6 +4200,9 @@ namespace HyperTwistTrainingSubsystemInternal
Health.Capabilities.AddUnique(TEXT("providerUsageCostDashboardShell"));
Health.Capabilities.AddUnique(TEXT("providerQuotaEscalationBanner"));
Health.Capabilities.AddUnique(TEXT("providerRouteCostDiagnostics"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostHistoryShell"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostExportPreview"));
Health.Capabilities.AddUnique(TEXT("providerUsageCostSummaryCopy"));
}
bool IsSpeechPermissionError(const FString& ErrorText)
@ -4604,6 +4697,352 @@ namespace HyperTwistTrainingSubsystemInternal
}
}
FString BuildSpeechUsageCostHistorySourceKind(
const FHyperTwistTrainingCompanionSpeechSessionState& SessionState
)
{
if (!SessionState.LastError.IsEmpty() && !SessionState.ServiceHealth.bReady)
{
return TEXT("provider-fallback-health");
}
if (!SessionState.bSessionOpen && !SessionState.OpenedAtUtc.IsEmpty())
{
return TEXT("session-closed-health");
}
if (SessionState.bHasTranscriptResult)
{
return TEXT("post-transcript-health");
}
if (SessionState.bSessionOpen)
{
return TEXT("session-open-health");
}
return TEXT("service-health-snapshot");
}
FString BuildSpeechUsageCostHistorySignature(
const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
const FHyperTwistSpeechUsageCostDashboardShellState& DashboardState,
const FString& SourceKind
)
{
return FString::Printf(
TEXT("%s|%s|%s|%s|%s|%s|%s|%d|%d|%d|%d|%d"),
*SourceKind,
*DashboardState.LatestUsageEventId,
*DashboardState.LatestCostEventId,
*DashboardState.LatestQuotaStateId,
*DashboardState.LatestRouteDecisionId,
*DashboardState.ActiveRouteStateId,
*SessionState.LastError,
SessionState.SubmittedUtteranceCount,
SessionState.FinalTranscriptCount,
DashboardState.bRouteReady ? 1 : 0,
DashboardState.bQuotaKnown ? 1 : 0,
SessionState.bSessionOpen ? 1 : 0
);
}
FHyperTwistSpeechUsageCostHistoryEntry BuildSpeechUsageCostHistoryEntry(
const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
const FHyperTwistSpeechUsageCostDashboardShellState& DashboardState,
const FString& SourceKind,
const int32 EntryOrdinal
)
{
FHyperTwistSpeechUsageCostHistoryEntry Entry;
const FString EffectiveSessionId =
!SessionState.ActiveSessionId.IsEmpty()
? SessionState.ActiveSessionId
: (!SessionState.SessionConfig.SessionId.IsEmpty()
? SessionState.SessionConfig.SessionId
: TEXT("speech-session-default"));
Entry.HistoryEntryId = FString::Printf(
TEXT("speech-usage-cost-history/%s/%02d"),
*EffectiveSessionId,
FMath::Max(EntryOrdinal, 1)
);
Entry.SourceKind = SourceKind;
Entry.SessionId = EffectiveSessionId;
Entry.ProviderProfileId = DashboardState.ActiveProviderProfileId;
Entry.ServiceLaneId = DashboardState.ActiveServiceLaneId;
Entry.UsageEventId = DashboardState.LatestUsageEventId;
Entry.CostEventId = DashboardState.LatestCostEventId;
Entry.QuotaStateId = DashboardState.LatestQuotaStateId;
Entry.RouteDecisionId = DashboardState.LatestRouteDecisionId;
Entry.CapturedAtUtc = !SessionState.LastUpdatedAtUtc.IsEmpty()
? SessionState.LastUpdatedAtUtc
: FDateTime::UtcNow().ToIso8601();
Entry.UsageQuantity = DashboardState.DisplayedUsageQuantity;
Entry.EstimatedCostUsd = DashboardState.DisplayedEstimatedCostUsd;
Entry.ReportedCostUsd = DashboardState.DisplayedReportedCostUsd;
Entry.RemainingEstimatedSpendUsd = DashboardState.RemainingEstimatedSpendUsd;
Entry.RemainingRequestCount = DashboardState.RemainingRequestCount;
Entry.RemainingAudioSeconds = DashboardState.RemainingAudioSeconds;
Entry.bEstimateOnly = DashboardState.bEstimateBadgeVisible;
Entry.bProviderReceiptPosted = DashboardState.bProviderReceiptPosted;
Entry.bQuotaKnown = DashboardState.bQuotaKnown;
Entry.bRateLimited = DashboardState.bRateLimited;
Entry.bHardBlocked = DashboardState.bHardBlocked;
Entry.bRouteReady = DashboardState.bRouteReady;
return Entry;
}
void AddSpeechUsageCostHistoryExportIssue(
FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState,
const FHyperTwistSpeechUsageCostHistoryExportIssue& Issue
)
{
if (!Issue.IsStructurallyValid())
{
return;
}
ShellState.Issues.Add(Issue);
if (!ShellState.ActiveIssue.IsStructurallyValid())
{
ShellState.ActiveIssue = Issue;
}
}
void AppendSpeechUsageCostHistoryEntry(
const FHyperTwistSpeechUsageCostHistoryExportShellProfile& Profile,
const FString& Signature,
const FHyperTwistSpeechUsageCostHistoryEntry& Entry,
FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState
)
{
if (!Entry.IsStructurallyValid() || ShellState.LastRecordedSignature == Signature)
{
return;
}
ShellState.HistoryEntries.Add(Entry);
while (ShellState.HistoryEntries.Num() > Profile.RetainedHistoryEntryLimit)
{
ShellState.HistoryEntries.RemoveAt(0);
}
ShellState.LastRecordedSignature = Signature;
}
void ApplySpeechUsageCostHistoryExportPosture(
const FHyperTwistSpeechUsageCostHistoryExportShellProfile& Profile,
const FHyperTwistTrainingCompanionSpeechSessionState& SessionState,
FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState
)
{
const FHyperTwistSpeechUsageCostDashboardShellState& DashboardState =
SessionState.UsageCostDashboardShellState;
const FString SourceKind = BuildSpeechUsageCostHistorySourceKind(SessionState);
ShellState.ActiveProviderProfileId = DashboardState.ActiveProviderProfileId;
ShellState.ActiveProviderDisplayLabel = DashboardState.ActiveProviderDisplayLabel;
ShellState.ActiveServiceLaneId = DashboardState.ActiveServiceLaneId;
ShellState.SelectedHistoryWindowId = !DashboardState.UsageAggregationWindowId.IsEmpty()
? DashboardState.UsageAggregationWindowId
: TEXT("current-session");
ShellState.ExportPreviewFormatId = Profile.ExportSurfaceMode;
ShellState.bHistoryVisible = Profile.bSupportsHistoryTimeline;
ShellState.bExportPreviewVisible = Profile.bSupportsExportPreview;
const FString Signature = BuildSpeechUsageCostHistorySignature(
SessionState,
DashboardState,
SourceKind
);
AppendSpeechUsageCostHistoryEntry(
Profile,
Signature,
BuildSpeechUsageCostHistoryEntry(
SessionState,
DashboardState,
SourceKind,
ShellState.HistoryEntries.Num() + 1
),
ShellState
);
ShellState.TotalUsageQuantity = 0.0f;
ShellState.TotalEstimatedCostUsd = 0.0f;
ShellState.TotalReportedCostUsd = 0.0f;
ShellState.LowestRemainingEstimatedSpendUsd = 0.0f;
ShellState.EstimateOnlyEntryCount = 0;
ShellState.ProviderReceiptEntryCount = 0;
ShellState.Issues.Reset();
ShellState.ActiveIssue = FHyperTwistSpeechUsageCostHistoryExportIssue();
for (int32 EntryIndex = 0; EntryIndex < ShellState.HistoryEntries.Num(); ++EntryIndex)
{
const FHyperTwistSpeechUsageCostHistoryEntry& HistoryEntry = ShellState.HistoryEntries[EntryIndex];
ShellState.TotalUsageQuantity += HistoryEntry.UsageQuantity;
ShellState.TotalEstimatedCostUsd += HistoryEntry.EstimatedCostUsd;
ShellState.TotalReportedCostUsd += HistoryEntry.ReportedCostUsd;
ShellState.LowestRemainingEstimatedSpendUsd =
EntryIndex == 0
? HistoryEntry.RemainingEstimatedSpendUsd
: FMath::Min(
ShellState.LowestRemainingEstimatedSpendUsd,
HistoryEntry.RemainingEstimatedSpendUsd
);
if (HistoryEntry.bEstimateOnly)
{
++ShellState.EstimateOnlyEntryCount;
}
if (HistoryEntry.bProviderReceiptPosted)
{
++ShellState.ProviderReceiptEntryCount;
}
}
ShellState.HistoryEntryCount = ShellState.HistoryEntries.Num();
ShellState.bExportPreviewReady = ShellState.HistoryEntries.Num() > 0;
ShellState.bCopySummaryReady =
Profile.bSupportsCopySummary && ShellState.bExportPreviewReady;
ShellState.bEstimateWatermarkVisible =
Profile.bSupportsEstimateWatermark && ShellState.EstimateOnlyEntryCount > 0;
ShellState.LatestSourceKind = SourceKind;
ShellState.LatestHistoryEntryId = ShellState.HistoryEntries.Num() > 0
? ShellState.HistoryEntries.Last().HistoryEntryId
: FString();
if (ShellState.HistoryEntries.Num() <= 0)
{
FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
Issue.IssueId = TEXT("provider-usage-cost-history-empty");
Issue.IssueKind = TEXT("no-history");
Issue.StatusLine = TEXT("Provider usage/cost history not captured yet.");
Issue.DetailLine =
TEXT("Refresh the provider usage/cost surfaces before relying on export preview output.");
Issue.RecommendedActionId = Profile.RefreshActionId;
AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
ShellState.StatusLine = Issue.StatusLine;
ShellState.DetailLine = Issue.DetailLine;
}
else
{
const FHyperTwistSpeechUsageCostHistoryEntry& LatestEntry = ShellState.HistoryEntries.Last();
ShellState.LatestSourceKind = LatestEntry.SourceKind;
if (!LatestEntry.bRouteReady || (!SessionState.LastError.IsEmpty() && !SessionState.ServiceHealth.bReady))
{
FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
Issue.IssueId = TEXT("provider-usage-cost-history-route-degraded");
Issue.IssueKind = TEXT("route-degraded");
Issue.StatusLine = TEXT("Provider history captured with route degradation.");
Issue.DetailLine = SessionState.LastError.IsEmpty()
? TEXT("The latest history snapshot came from a degraded provider route. Review the route before treating export preview output as current operating posture.")
: FString::Printf(
TEXT("The latest history snapshot captured '%s'. Review the route before treating export preview output as current operating posture."),
*SessionState.LastError
);
Issue.RecommendedActionId = Profile.RouteInspectActionId;
AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
}
else if (LatestEntry.bHardBlocked)
{
FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
Issue.IssueId = TEXT("provider-usage-cost-history-hard-blocked");
Issue.IssueKind = TEXT("hard-blocked");
Issue.StatusLine = TEXT("Provider history shows hard-blocked budget posture.");
Issue.DetailLine =
TEXT("The latest history snapshot reflects a hard-blocked provider budget posture. Review budget state before relying on more provider-backed capture.");
Issue.RecommendedActionId = Profile.BudgetInspectActionId;
AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
}
else if (LatestEntry.bRateLimited)
{
FHyperTwistSpeechUsageCostHistoryExportIssue Issue;
Issue.IssueId = TEXT("provider-usage-cost-history-rate-limited");
Issue.IssueKind = TEXT("rate-limited");
Issue.StatusLine = TEXT("Provider history shows rate-limited posture.");
Issue.DetailLine =
TEXT("The latest history snapshot reflects a rate-limited provider route. Review budget state before relying on more provider-backed capture.");
Issue.RecommendedActionId = Profile.BudgetInspectActionId;
AddSpeechUsageCostHistoryExportIssue(ShellState, Issue);
}
if (ShellState.ActiveIssue.IsStructurallyValid())
{
ShellState.StatusLine = ShellState.ActiveIssue.StatusLine;
ShellState.DetailLine = ShellState.ActiveIssue.DetailLine;
}
else
{
ShellState.StatusLine = TEXT("Provider usage/cost history ready for operator preview.");
ShellState.DetailLine = FString::Printf(
TEXT("%d snapshots retain %.2f %s and %.2f USD estimated cost for %s."),
ShellState.HistoryEntryCount,
ShellState.TotalUsageQuantity,
*DashboardState.UsageMeterKind,
ShellState.TotalEstimatedCostUsd,
*ShellState.ActiveProviderDisplayLabel
);
}
}
ShellState.ExportPreviewText = FString::Printf(
TEXT("providerProfileId=%s\nserviceLaneId=%s\nhistoryEntryCount=%d\nlatestSourceKind=%s\ntotalUsageQuantity=%.2f\n")
TEXT("totalEstimatedCostUsd=%.2f\ntotalReportedCostUsd=%.2f\nestimateOnlyEntryCount=%d\nproviderReceiptEntryCount=%d\n")
TEXT("lowestRemainingEstimatedSpendUsd=%.2f\nlatestHistoryEntryId=%s\nlastError=%s"),
*ShellState.ActiveProviderProfileId,
*ShellState.ActiveServiceLaneId,
ShellState.HistoryEntryCount,
*ShellState.LatestSourceKind,
ShellState.TotalUsageQuantity,
ShellState.TotalEstimatedCostUsd,
ShellState.TotalReportedCostUsd,
ShellState.EstimateOnlyEntryCount,
ShellState.ProviderReceiptEntryCount,
ShellState.LowestRemainingEstimatedSpendUsd,
*ShellState.LatestHistoryEntryId,
*SessionState.LastError
);
ShellState.ActiveIssueCount = ShellState.Issues.Num();
}
void SynchronizeSpeechUsageCostHistoryExportState(
FHyperTwistTrainingCompanionSpeechSessionState& SessionState
)
{
FHyperTwistSpeechSessionConfig EffectiveConfig = SessionState.SessionConfig;
ApplySpeechUsageCostDefaults(EffectiveConfig);
if (!SessionState.UsageCostHistoryExportShellState.IsStructurallyValid())
{
SessionState.UsageCostHistoryExportShellState =
BuildSpeechUsageCostHistoryExportShellState(EffectiveConfig, &SessionState);
}
const FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile =
EffectiveConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid()
? EffectiveConfig.UsageCostHistoryExportShellProfileDefinition
: BuildDefaultSpeechUsageCostHistoryExportShellProfile(
!EffectiveConfig.UsageCostHistoryExportShellProfileId.IsEmpty()
? EffectiveConfig.UsageCostHistoryExportShellProfileId
: TEXT("speech-provider-usage-cost-history-export-shell-v1")
);
FHyperTwistSpeechUsageCostHistoryExportShellState& ShellState =
SessionState.UsageCostHistoryExportShellState;
ShellState.HistoryExportShellProfileId = Profile.HistoryExportShellProfileId;
ShellState.AvailableActionIds.Reset();
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
{
ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
}
ApplySpeechUsageCostHistoryExportPosture(Profile, SessionState, ShellState);
ShellState.AvailableActionIds.AddUnique(Profile.RefreshActionId);
ShellState.AvailableActionIds.AddUnique(Profile.ExportPreviewActionId);
ShellState.AvailableActionIds.AddUnique(Profile.CopySummaryActionId);
ShellState.AvailableActionIds.AddUnique(Profile.RouteInspectActionId);
ShellState.AvailableActionIds.AddUnique(Profile.BudgetInspectActionId);
if (ShellState.ActiveIssue.IsStructurallyValid())
{
ShellState.AvailableActionIds.AddUnique(ShellState.ActiveIssue.RecommendedActionId);
}
}
FHyperTwistSpeechMicrophoneShellState BuildCoachCommandMicrophoneShellState(
const FHyperTwistSpeechSessionConfig& SessionConfig,
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState,
@ -4759,6 +5198,55 @@ namespace HyperTwistTrainingSubsystemInternal
return ShellState;
}
FHyperTwistSpeechUsageCostHistoryExportShellState BuildSpeechUsageCostHistoryExportShellState(
const FHyperTwistSpeechSessionConfig& SessionConfig,
const FHyperTwistTrainingCompanionSpeechSessionState* PriorState
)
{
const FHyperTwistSpeechUsageCostHistoryExportShellProfile Profile =
SessionConfig.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid()
? SessionConfig.UsageCostHistoryExportShellProfileDefinition
: BuildDefaultSpeechUsageCostHistoryExportShellProfile(
!SessionConfig.UsageCostHistoryExportShellProfileId.IsEmpty()
? SessionConfig.UsageCostHistoryExportShellProfileId
: TEXT("speech-provider-usage-cost-history-export-shell-v1")
);
FHyperTwistSpeechUsageCostHistoryExportShellState ShellState;
ShellState.HistoryExportShellProfileId = Profile.HistoryExportShellProfileId;
ShellState.ActiveProviderProfileId = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
? SessionConfig.ProviderProfileDefinition.ProviderProfileId
: TEXT("speech-provider/local-http-sidecar-profile-v1");
ShellState.ActiveProviderDisplayLabel = SessionConfig.ProviderProfileDefinition.IsStructurallyValid()
? SessionConfig.ProviderProfileDefinition.DisplayLabel
: TEXT("Local HTTP Speech Sidecar");
ShellState.ActiveServiceLaneId = !SessionConfig.OrchestrationProfile.ServiceLaneId.IsEmpty()
? SessionConfig.OrchestrationProfile.ServiceLaneId
: TEXT("speech/python-service");
ShellState.SelectedHistoryWindowId = !SessionConfig.UsageEventTemplate.AggregationWindowId.IsEmpty()
? SessionConfig.UsageEventTemplate.AggregationWindowId
: TEXT("current-session");
ShellState.ExportPreviewFormatId = Profile.ExportSurfaceMode;
ShellState.bHistoryVisible = Profile.bSupportsHistoryTimeline;
ShellState.bExportPreviewVisible = Profile.bSupportsExportPreview;
ShellState.bEstimateWatermarkVisible = Profile.bSupportsEstimateWatermark;
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : Profile.ActionBindings)
{
ShellState.AvailableActionIds.AddUnique(ActionBinding.ActionId);
}
if (PriorState != nullptr
&& PriorState->UsageCostHistoryExportShellState.HistoryExportShellProfileId
== Profile.HistoryExportShellProfileId)
{
ShellState = PriorState->UsageCostHistoryExportShellState;
ShellState.HistoryExportShellProfileId = Profile.HistoryExportShellProfileId;
ShellState.ExportPreviewFormatId = Profile.ExportSurfaceMode;
}
return ShellState;
}
FHyperTwistVisionCorrectionState BuildClassicCubeCorrectionState(
const FHyperTwistVisionSessionConfig& SessionConfig,
const FHyperTwistVisionReconstructionSession& ReconstructionSession,
@ -10124,6 +10612,16 @@ bool UHyperTwistTrainingSubsystem::OpenActiveCompanionSpeechSession(FString& Out
return true;
}
ActiveCompanionSpeechSessionState.SubmittedUtteranceCount = 0;
ActiveCompanionSpeechSessionState.FinalTranscriptCount = 0;
ActiveCompanionSpeechSessionState.bHasTranscriptResult = false;
ActiveCompanionSpeechSessionState.LastTranscriptResult = FHyperTwistSpeechTranscriptResult();
ActiveCompanionSpeechSessionState.UsageCostHistoryExportShellState =
HyperTwistTrainingSubsystemInternal::BuildSpeechUsageCostHistoryExportShellState(
SessionConfig,
nullptr
);
if (ActiveCompanionSpeechSessionState.bSessionOpen
&& ActiveCompanionSpeechSessionState.ActiveSessionId != SessionConfig.SessionId)
{
@ -10197,6 +10695,9 @@ FHyperTwistSpeechTranscriptResult UHyperTwistTrainingSubsystem::SubmitActiveComp
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
ActiveCompanionSpeechSessionState
);
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
ActiveCompanionSpeechSessionState
);
return Result;
}
@ -10368,6 +10869,12 @@ FHyperTwistSpeechTranscriptResult UHyperTwistTrainingSubsystem::SubmitActiveComp
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechMicrophoneShellState(
ActiveCompanionSpeechSessionState
);
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
ActiveCompanionSpeechSessionState
);
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
ActiveCompanionSpeechSessionState
);
return Result;
}
@ -11114,6 +11621,9 @@ void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth()
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
ActiveCompanionSpeechSessionState
);
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
ActiveCompanionSpeechSessionState
);
return;
}
@ -11142,6 +11652,9 @@ void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth()
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostDashboardState(
ActiveCompanionSpeechSessionState
);
HyperTwistTrainingSubsystemInternal::SynchronizeSpeechUsageCostHistoryExportState(
ActiveCompanionSpeechSessionState
);
}
void UHyperTwistTrainingSubsystem::AppendRecognitionReplayEvent(

View file

@ -2869,6 +2869,393 @@ struct FHyperTwistSpeechUsageCostDashboardShellState
}
};
USTRUCT(BlueprintType)
struct FHyperTwistSpeechUsageCostHistoryExportShellProfile
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString HistoryExportShellProfileId = TEXT("speech-provider-usage-cost-history-export-shell-v1");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ShellKind = TEXT("operator-usage-cost-history-export");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString HistorySurfaceMode = TEXT("rolling-usage-cost-snapshot-history");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ExportSurfaceMode = TEXT("first-party-summary-preview");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RefreshActionId = TEXT("refresh-provider-usage-cost-history");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ExportPreviewActionId = TEXT("preview-provider-usage-cost-export");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString CopySummaryActionId = TEXT("copy-provider-usage-cost-summary");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RouteInspectActionId = TEXT("inspect-provider-route");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString BudgetInspectActionId = TEXT("review-provider-budget");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RetainedHistoryEntryLimit = 12;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSupportsHistoryTimeline = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSupportsExportPreview = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSupportsCopySummary = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bSupportsEstimateWatermark = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bPreservesFirstPartySummaryOwnership = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FHyperTwistSpeechShellPanelLayout> Panels;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FHyperTwistSpeechShellActionBinding> ActionBindings;
bool IsStructurallyValid() const
{
if (HistoryExportShellProfileId.IsEmpty()
|| ShellKind.IsEmpty()
|| HistorySurfaceMode.IsEmpty()
|| ExportSurfaceMode.IsEmpty()
|| RefreshActionId.IsEmpty()
|| ExportPreviewActionId.IsEmpty()
|| CopySummaryActionId.IsEmpty()
|| RouteInspectActionId.IsEmpty()
|| BudgetInspectActionId.IsEmpty()
|| RetainedHistoryEntryLimit <= 0
|| Panels.Num() <= 0
|| ActionBindings.Num() <= 0)
{
return false;
}
for (const FHyperTwistSpeechShellPanelLayout& Panel : Panels)
{
if (!Panel.IsStructurallyValid())
{
return false;
}
}
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : ActionBindings)
{
if (!ActionBinding.IsStructurallyValid())
{
return false;
}
}
return true;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistSpeechUsageCostHistoryEntry
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString HistoryEntryId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SourceKind = TEXT("service-health-snapshot");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SessionId = TEXT("speech-session-default");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ServiceLaneId = TEXT("speech/python-service");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString UsageEventId = TEXT("speech-usage-event/current-session");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString CostEventId = TEXT("speech-cost-event/current-session");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString QuotaStateId = TEXT("speech-quota-state/current-session");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RouteDecisionId = TEXT("speech-route-decision/current-session");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString CapturedAtUtc = TEXT("2026-05-25T00:00:00Z");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float UsageQuantity = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float EstimatedCostUsd = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float ReportedCostUsd = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float RemainingEstimatedSpendUsd = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RemainingRequestCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 RemainingAudioSeconds = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bEstimateOnly = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bProviderReceiptPosted = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bQuotaKnown = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bRateLimited = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHardBlocked = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bRouteReady = true;
bool IsStructurallyValid() const
{
return !HistoryEntryId.IsEmpty()
&& !SourceKind.IsEmpty()
&& !SessionId.IsEmpty()
&& !ProviderProfileId.IsEmpty()
&& !ServiceLaneId.IsEmpty()
&& !UsageEventId.IsEmpty()
&& !CostEventId.IsEmpty()
&& !QuotaStateId.IsEmpty()
&& !RouteDecisionId.IsEmpty()
&& !CapturedAtUtc.IsEmpty()
&& UsageQuantity >= 0.0f
&& EstimatedCostUsd >= 0.0f
&& ReportedCostUsd >= 0.0f
&& RemainingEstimatedSpendUsd >= 0.0f
&& RemainingRequestCount >= 0
&& RemainingAudioSeconds >= 0;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistSpeechUsageCostHistoryExportIssue
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString IssueId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString IssueKind;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString StatusLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DetailLine;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString RecommendedActionId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bRequiresOperatorAttention = true;
bool IsStructurallyValid() const
{
return !IssueId.IsEmpty()
&& !IssueKind.IsEmpty()
&& !StatusLine.IsEmpty()
&& !DetailLine.IsEmpty()
&& !RecommendedActionId.IsEmpty();
}
};
USTRUCT(BlueprintType)
struct FHyperTwistSpeechUsageCostHistoryExportShellState
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString HistoryExportShellProfileId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActiveProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActiveProviderDisplayLabel = TEXT("Local HTTP Speech Sidecar");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActiveServiceLaneId = TEXT("speech/python-service");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString SelectedHistoryWindowId = TEXT("current-session");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ExportPreviewFormatId = TEXT("first-party-summary-preview");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LatestHistoryEntryId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LatestSourceKind = TEXT("service-health-snapshot");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString StatusLine = TEXT("Provider usage/cost history ready for operator preview.");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString DetailLine = TEXT("First-party usage/cost history is ready for bounded preview and copy surfaces.");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ExportPreviewText;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 HistoryEntryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 EstimateOnlyEntryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ProviderReceiptEntryCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float TotalUsageQuantity = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float TotalEstimatedCostUsd = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float TotalReportedCostUsd = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
float LowestRemainingEstimatedSpendUsd = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHistoryVisible = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bExportPreviewVisible = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bEstimateWatermarkVisible = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bExportPreviewReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bCopySummaryReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ActiveIssueCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistSpeechUsageCostHistoryExportIssue ActiveIssue;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FHyperTwistSpeechUsageCostHistoryExportIssue> Issues;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FHyperTwistSpeechUsageCostHistoryEntry> HistoryEntries;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
TArray<FString> AvailableActionIds;
FString LastRecordedSignature;
bool IsStructurallyValid() const
{
if (HistoryExportShellProfileId.IsEmpty()
|| ActiveProviderProfileId.IsEmpty()
|| ActiveProviderDisplayLabel.IsEmpty()
|| ActiveServiceLaneId.IsEmpty()
|| SelectedHistoryWindowId.IsEmpty()
|| ExportPreviewFormatId.IsEmpty()
|| LatestSourceKind.IsEmpty()
|| StatusLine.IsEmpty()
|| DetailLine.IsEmpty()
|| HistoryEntryCount < 0
|| EstimateOnlyEntryCount < 0
|| ProviderReceiptEntryCount < 0
|| TotalUsageQuantity < 0.0f
|| TotalEstimatedCostUsd < 0.0f
|| TotalReportedCostUsd < 0.0f
|| LowestRemainingEstimatedSpendUsd < 0.0f
|| ActiveIssueCount < 0
|| AvailableActionIds.Num() <= 0)
{
return false;
}
if (HistoryEntryCount != HistoryEntries.Num())
{
return false;
}
if (HistoryEntryCount > 0 && LatestHistoryEntryId.IsEmpty())
{
return false;
}
if (bExportPreviewReady && ExportPreviewText.IsEmpty())
{
return false;
}
if (ActiveIssueCount != Issues.Num())
{
return false;
}
if (ActiveIssueCount > 0 && !ActiveIssue.IsStructurallyValid())
{
return false;
}
for (const FHyperTwistSpeechUsageCostHistoryExportIssue& Issue : Issues)
{
if (!Issue.IsStructurallyValid())
{
return false;
}
}
for (const FHyperTwistSpeechUsageCostHistoryEntry& HistoryEntry : HistoryEntries)
{
if (!HistoryEntry.IsStructurallyValid())
{
return false;
}
}
for (const FString& ActionId : AvailableActionIds)
{
if (ActionId.IsEmpty())
{
return false;
}
}
return true;
}
};
USTRUCT(BlueprintType)
struct FHyperTwistSpeechSessionConfig
{
@ -2946,6 +3333,14 @@ struct FHyperTwistSpeechSessionConfig
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistSpeechUsageCostDashboardShellProfile UsageCostDashboardShellProfileDefinition;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString UsageCostHistoryExportShellProfileId =
TEXT("speech-provider-usage-cost-history-export-shell-v1");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistSpeechUsageCostHistoryExportShellProfile
UsageCostHistoryExportShellProfileDefinition;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1");
@ -2994,6 +3389,8 @@ struct FHyperTwistSpeechSessionConfig
|| !CostEventTemplate.IsStructurallyValid()
|| UsageCostDashboardShellProfileId.IsEmpty()
|| !UsageCostDashboardShellProfileDefinition.IsStructurallyValid()
|| UsageCostHistoryExportShellProfileId.IsEmpty()
|| !UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid()
|| PayloadCustodyProfileId.IsEmpty()
|| !PayloadCustodyProfileDefinition.IsStructurallyValid()
|| RequiredModelPayloads.Num() <= 0

View file

@ -1943,6 +1943,9 @@ struct FHyperTwistTrainingCompanionSpeechSessionState
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistSpeechUsageCostDashboardShellState UsageCostDashboardShellState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistSpeechUsageCostHistoryExportShellState UsageCostHistoryExportShellState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FHyperTwistSpeechTranscriptResult LastTranscriptResult;
};

View file

@ -0,0 +1,282 @@
// Copyright HyperTwist, Inc. All Rights Reserved.
#include "Misc/AutomationTest.h"
#include "Engine/GameInstance.h"
#include "HyperTwistRecognition/HyperTwistSpeechClient.h"
#include "HyperTwistTraining/HyperTwistTrainingSubsystem.h"
#include "UObject/UnrealType.h"
#if WITH_AUTOMATION_TESTS
namespace HyperTwistWhisperCppPhase6RABTestInternal
{
FHyperTwistTrainingDeck MakeSpeechDeck()
{
FHyperTwistTrainingDeck Deck;
Deck.DeckId = TEXT("phase6r-ab/provider-usage-cost-history-export");
Deck.Title = TEXT("Phase 6R-AB Provider Usage/Cost History Export");
Deck.DeliveryModes = {
EHyperTwistTrainingDeliveryMode::CoachReviewed
};
FHyperTwistTrainingCase TrainingCase;
TrainingCase.CaseId = TEXT("phase6r-ab-case");
TrainingCase.PuzzleId = TEXT("cube/3x3x3");
TrainingCase.PromptKind = EHyperTwistTrainingPromptKind::Sequence;
TrainingCase.PromptLabel = TEXT("Phase 6R-AB Coach Speech");
TrainingCase.AllowedDeliveryModes = {
EHyperTwistTrainingDeliveryMode::CoachReviewed
};
Deck.Cases = {TrainingCase};
return Deck;
}
void ForceSpeechClientKind(UHyperTwistTrainingSubsystem* TrainingSubsystem, const FString& ClientKind)
{
if (TrainingSubsystem == nullptr)
{
return;
}
if (FStrProperty* SpeechClientKindProperty = FindFProperty<FStrProperty>(
UHyperTwistTrainingSubsystem::StaticClass(),
TEXT("CompanionSpeechClientKind")
))
{
SpeechClientKindProperty->SetPropertyValue_InContainer(TrainingSubsystem, ClientKind);
}
}
UHyperTwistTrainingSubsystem* MakeSpeechSubsystem(const FString& SessionId, const FString& ClientKind)
{
UGameInstance* GameInstance = NewObject<UGameInstance>(GetTransientPackage());
if (GameInstance == nullptr)
{
return nullptr;
}
UHyperTwistTrainingSubsystem* TrainingSubsystem = NewObject<UHyperTwistTrainingSubsystem>(GameInstance);
if (TrainingSubsystem == nullptr)
{
return nullptr;
}
ForceSpeechClientKind(TrainingSubsystem, ClientKind);
const FHyperTwistTrainingRunState RunState = TrainingSubsystem->StartTrainingRunFromDeck(
MakeSpeechDeck(),
TEXT("phase6r-ab-user"),
SessionId,
EHyperTwistTrainingDeliveryMode::CoachReviewed
);
return RunState.IsStructurallyValid() ? TrainingSubsystem : nullptr;
}
UHyperTwistHttpSpeechClient* ResolveHttpSpeechClient(UHyperTwistTrainingSubsystem* TrainingSubsystem)
{
if (TrainingSubsystem == nullptr)
{
return nullptr;
}
FString CloseError;
TrainingSubsystem->CloseActiveCompanionSpeechSession(CloseError);
if (FObjectPropertyBase* ClientProperty = FindFProperty<FObjectPropertyBase>(
UHyperTwistTrainingSubsystem::StaticClass(),
TEXT("ActiveCompanionSpeechClientObject")
))
{
return Cast<UHyperTwistHttpSpeechClient>(
ClientProperty->GetObjectPropertyValue_InContainer(TrainingSubsystem)
);
}
return nullptr;
}
FHyperTwistSpeechUtteranceEnvelope MakeUtterance()
{
FHyperTwistSpeechUtteranceEnvelope Utterance;
Utterance.AudioRef = TEXT("ready-coach");
Utterance.SpeechStartMs = 120;
Utterance.SpeechEndMs = 840;
Utterance.SilenceGapMs = 240;
return Utterance;
}
bool ContainsPanelId(
const TArray<FHyperTwistSpeechShellPanelLayout>& Panels,
const FString& ExpectedPanelId
)
{
for (const FHyperTwistSpeechShellPanelLayout& Panel : Panels)
{
if (Panel.PanelId == ExpectedPanelId)
{
return true;
}
}
return false;
}
bool ContainsActionId(
const TArray<FHyperTwistSpeechShellActionBinding>& ActionBindings,
const FString& ExpectedActionId
)
{
for (const FHyperTwistSpeechShellActionBinding& ActionBinding : ActionBindings)
{
if (ActionBinding.ActionId == ExpectedActionId)
{
return true;
}
}
return false;
}
}
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FHyperTwistWhisperCppPhase6RABUsageCostHistoryExportSessionConfigTest,
"HyperTwist.Permissive.WhisperCpp.Phase6R.AB.UsageCostHistoryExportSessionConfig",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)
bool FHyperTwistWhisperCppPhase6RABUsageCostHistoryExportSessionConfigTest::RunTest(const FString& Parameters)
{
UHyperTwistTrainingSubsystem* TrainingSubsystem =
HyperTwistWhisperCppPhase6RABTestInternal::MakeSpeechSubsystem(
TEXT("phase6r-ab-config-session"),
TEXT("mock")
);
TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-AB."), TrainingSubsystem);
if (TrainingSubsystem == nullptr)
{
return false;
}
FString OpenError;
TestTrue(TEXT("The mock history/export route must open a speech session."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError));
TestTrue(TEXT("Opening the mock history/export speech session must not report an error."), OpenError.IsEmpty());
const FHyperTwistSpeechSessionConfig& Config =
TrainingSubsystem->GetActiveCompanionSpeechSessionState().SessionConfig;
TestTrue(TEXT("The history/export session config must remain structurally valid."), Config.IsStructurallyValid());
TestEqual(TEXT("The history/export shell profile id must be present."), Config.UsageCostHistoryExportShellProfileId, TEXT("speech-provider-usage-cost-history-export-shell-v1"));
TestTrue(TEXT("The history/export shell profile must remain structurally valid."), Config.UsageCostHistoryExportShellProfileDefinition.IsStructurallyValid());
TestEqual(TEXT("The history/export shell must preserve the operator-facing shell kind."), Config.UsageCostHistoryExportShellProfileDefinition.ShellKind, TEXT("operator-usage-cost-history-export"));
TestEqual(TEXT("The history/export shell must preserve the export preview action id."), Config.UsageCostHistoryExportShellProfileDefinition.ExportPreviewActionId, TEXT("preview-provider-usage-cost-export"));
TestEqual(TEXT("The history/export shell must preserve the copy summary action id."), Config.UsageCostHistoryExportShellProfileDefinition.CopySummaryActionId, TEXT("copy-provider-usage-cost-summary"));
TestTrue(TEXT("The history/export shell must include the history timeline panel."), HyperTwistWhisperCppPhase6RABTestInternal::ContainsPanelId(Config.UsageCostHistoryExportShellProfileDefinition.Panels, TEXT("history-timeline-card")));
TestTrue(TEXT("The history/export shell must include the export preview action."), HyperTwistWhisperCppPhase6RABTestInternal::ContainsActionId(Config.UsageCostHistoryExportShellProfileDefinition.ActionBindings, TEXT("preview-provider-usage-cost-export")));
return true;
}
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FHyperTwistWhisperCppPhase6RABUsageCostHistoryExportShellStateTest,
"HyperTwist.Permissive.WhisperCpp.Phase6R.AB.UsageCostHistoryExportShellState",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)
bool FHyperTwistWhisperCppPhase6RABUsageCostHistoryExportShellStateTest::RunTest(const FString& Parameters)
{
UHyperTwistTrainingSubsystem* TrainingSubsystem =
HyperTwistWhisperCppPhase6RABTestInternal::MakeSpeechSubsystem(
TEXT("phase6r-ab-shell-session"),
TEXT("mock")
);
TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-AB."), TrainingSubsystem);
if (TrainingSubsystem == nullptr)
{
return false;
}
FString OpenError;
TestTrue(TEXT("The mock history/export route must open a speech session."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError));
TestTrue(TEXT("Opening the mock history/export speech session must not report an error."), OpenError.IsEmpty());
const FHyperTwistSpeechTranscriptResult Result =
TrainingSubsystem->SubmitActiveCompanionSpeechUtterance(
HyperTwistWhisperCppPhase6RABTestInternal::MakeUtterance()
);
TestTrue(TEXT("The mock history/export utterance must produce a final transcript."), Result.bIsFinal);
TestTrue(TEXT("The mock history/export utterance must remain structurally valid."), Result.IsStructurallyValid());
const FHyperTwistTrainingCompanionSpeechSessionState SessionState =
TrainingSubsystem->GetActiveCompanionSpeechSessionState();
const FHyperTwistSpeechServiceHealth& Health = SessionState.ServiceHealth;
const FHyperTwistSpeechUsageCostHistoryExportShellState& HistoryExport =
SessionState.UsageCostHistoryExportShellState;
TestTrue(TEXT("The service health must expose the usage/cost history shell."), Health.Capabilities.Contains(TEXT("providerUsageCostHistoryShell")));
TestTrue(TEXT("The service health must expose the usage/cost export preview capability."), Health.Capabilities.Contains(TEXT("providerUsageCostExportPreview")));
TestTrue(TEXT("The service health must expose the usage/cost summary copy capability."), Health.Capabilities.Contains(TEXT("providerUsageCostSummaryCopy")));
TestTrue(TEXT("The history/export shell state must remain structurally valid."), HistoryExport.IsStructurallyValid());
TestEqual(TEXT("The history/export shell must preserve the mock provider profile."), HistoryExport.ActiveProviderProfileId, TEXT("speech-provider/mock-offline-profile-v1"));
TestEqual(TEXT("The history/export shell must retain exactly two bounded snapshots after open and submit."), HistoryExport.HistoryEntryCount, 2);
TestEqual(TEXT("The history/export shell must preserve the latest source kind."), HistoryExport.LatestSourceKind, TEXT("post-transcript-health"));
TestTrue(TEXT("The history/export shell must preserve export preview readiness."), HistoryExport.bExportPreviewReady);
TestTrue(TEXT("The history/export shell must preserve copy-summary readiness."), HistoryExport.bCopySummaryReady);
TestTrue(TEXT("The history/export shell must preserve the export preview action."), HistoryExport.AvailableActionIds.Contains(TEXT("preview-provider-usage-cost-export")));
TestTrue(TEXT("The history/export shell must preserve the copy summary action."), HistoryExport.AvailableActionIds.Contains(TEXT("copy-provider-usage-cost-summary")));
TestTrue(TEXT("The history/export shell must accumulate the mock usage quantity."), FMath::IsNearlyEqual(HistoryExport.TotalUsageQuantity, 1.50f));
TestTrue(TEXT("The history/export shell must accumulate the mock estimated cost."), FMath::IsNearlyEqual(HistoryExport.TotalEstimatedCostUsd, 0.02f));
TestEqual(TEXT("The history/export shell must preserve estimate-only entry count."), HistoryExport.EstimateOnlyEntryCount, 2);
TestTrue(TEXT("The history/export preview text must preserve the bounded history count."), HistoryExport.ExportPreviewText.Contains(TEXT("historyEntryCount=2")));
return true;
}
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FHyperTwistWhisperCppPhase6RABProviderBackedHistoryExportFallbackTest,
"HyperTwist.Permissive.WhisperCpp.Phase6R.AB.ProviderBackedHistoryExportFallback",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)
bool FHyperTwistWhisperCppPhase6RABProviderBackedHistoryExportFallbackTest::RunTest(const FString& Parameters)
{
UHyperTwistTrainingSubsystem* TrainingSubsystem =
HyperTwistWhisperCppPhase6RABTestInternal::MakeSpeechSubsystem(
TEXT("phase6r-ab-provider-session"),
TEXT("http-sidecar")
);
TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-AB."), TrainingSubsystem);
if (TrainingSubsystem == nullptr)
{
return false;
}
UHyperTwistHttpSpeechClient* HttpSpeechClient =
HyperTwistWhisperCppPhase6RABTestInternal::ResolveHttpSpeechClient(TrainingSubsystem);
TestNotNull(TEXT("The provider-backed speech client must be available for the history/export fallback test."), HttpSpeechClient);
if (HttpSpeechClient == nullptr)
{
return false;
}
HttpSpeechClient->ServiceBaseUrl.Reset();
FString OpenError;
TestFalse(TEXT("The provider-backed history/export path must fail cleanly when no provider endpoint is configured."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError));
TestEqual(TEXT("The provider-backed history/export path must report the missing service base URL."), OpenError, TEXT("service-base-url-missing"));
const FHyperTwistTrainingCompanionSpeechSessionState SessionState =
TrainingSubsystem->GetActiveCompanionSpeechSessionState();
const FHyperTwistSpeechUsageCostHistoryExportShellState& HistoryExport =
SessionState.UsageCostHistoryExportShellState;
TestTrue(TEXT("The provider-backed history/export fallback must remain structurally valid."), HistoryExport.IsStructurallyValid());
TestEqual(TEXT("The fallback history/export shell must preserve the sidecar profile id."), HistoryExport.ActiveProviderProfileId, TEXT("speech-provider/local-http-sidecar-profile-v1"));
TestEqual(TEXT("The fallback history/export shell must preserve the fallback source kind."), HistoryExport.LatestSourceKind, TEXT("provider-fallback-health"));
TestEqual(TEXT("The fallback history/export shell must preserve one history entry."), HistoryExport.HistoryEntryCount, 1);
TestEqual(TEXT("The fallback history/export shell must surface one active issue."), HistoryExport.ActiveIssueCount, 1);
TestEqual(TEXT("The fallback history/export shell must surface the route-degraded issue kind."), HistoryExport.ActiveIssue.IssueKind, TEXT("route-degraded"));
TestTrue(TEXT("The fallback history/export shell must still expose export preview readiness for first-party summary output."), HistoryExport.bExportPreviewReady);
TestTrue(TEXT("The fallback history/export preview text must preserve the missing-endpoint reason."), HistoryExport.ExportPreviewText.Contains(TEXT("service-base-url-missing")));
return true;
}
#endif

View file

@ -195,8 +195,12 @@ Status update on `2026-05-21`:
dashboard shell control pass is now consumed
- the bounded first-party `Phase 6R-AA` operator-facing provider usage/cost dashboard shell
packet is now landed in current code
- the current next bounded move is a source-backed `Phase 6R-AB` first-party provider
usage/cost history/export shell preparation/control pass, not a new restrictive packet by
- the generic source-backed `Phase 6R-AB` first-party provider usage/cost history/export shell
control pass is now consumed
- the bounded first-party `Phase 6R-AB` provider usage/cost history/export shell packet is now
landed in current code
- the current next bounded move is a source-backed `Phase 6R-AC` first-party provider receipt
review and posted-charge inspection preparation/control pass, not a new restrictive packet by
default
- use the repo-row README census, the portfolio standing refresh backfill, and the `2R-A`
ownership contract for the current queue after that correction
@ -346,8 +350,8 @@ Current practical interpretation:
- the landed `PostHog/posthog` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_D_POSTHOG_CONTROL_PLANE_IMPLEMENTATION_2026-05-13.md`
- the landed `screenpipe/screenpipe` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_E_SCREENPIPE_CAPTURE_HISTORY_IMPLEMENTATION_2026-05-13.md`
- the landed `remotion-dev/remotion` boundary-sensitive widening packet now lives in `docs/HYPERTWIST_PHASE_4R_PACKET_4R_F_REMOTION_MEDIA_EXPORT_IMPLEMENTATION_2026-05-13.md`
- the next bounded move is a source-backed `Phase 6R-AB` first-party provider usage/cost
history/export shell preparation/control pass
- the next bounded move is a source-backed `Phase 6R-AC` first-party provider receipt review and
posted-charge inspection preparation/control pass
Companion docs:

View file

@ -0,0 +1,163 @@
# HyperTwist Phase 6R-AB first-party provider usage/cost history/export shell implementation packet
Created on `2026-05-25`
## Status
- first-party HyperTwist packet
- bounded `Phase 6R-AB` implementation slice
## Purpose
This packet lands the next bounded first-party slice above the landed speech
session, microphone-shell, payload-custody, provider-custody,
provider-routing, normalized usage/cost event, and operator-facing
usage/cost dashboard seams.
The landed slice is:
- first-party provider usage/cost history/export shell
It is not:
- a provider receipt review packet
- an actual billing settlement packet
- an invoice reconciliation packet
- an actual payload-shipping packet
- a real device-permission workflow packet
- a native audio-device route ownership packet
- a provider-specific overlay packet
- a broad assistant-platform packet
## Current authority basis
This implementation packet stands on:
- `docs/ops/HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md`
- `docs/arch/HYPERTWIST_PHASE6R_AB_FIRST_PARTY_PROVIDER_USAGE_COST_HISTORY_EXPORT_SHELL_PREPARATION_PACKET_2026-05-25.md`
- `docs/arch/HYPERTWIST_PHASE6R_AA_FIRST_PARTY_OPERATOR_FACING_PROVIDER_USAGE_COST_DASHBOARD_SHELL_IMPLEMENTATION_PACKET_2026-05-25.md`
The preserved owners do not change:
- first-party HyperTwist remains the top-level provider/session owner
- first-party HyperTwist remains the usage/cost governance owner
- `ggml-org/whisper.cpp` remains bounded to offline STT donor seams
- `SYSTRAN/faster-whisper` remains bounded to complementary Python
orchestration/service-lane seams
## Landed scope
The current code now owns a bounded history/export seam through:
- retained recognition contract types for:
- `FHyperTwistSpeechUsageCostHistoryExportShellProfile`
- `FHyperTwistSpeechUsageCostHistoryEntry`
- `FHyperTwistSpeechUsageCostHistoryExportIssue`
- `FHyperTwistSpeechUsageCostHistoryExportShellState`
- expanded `FHyperTwistSpeechSessionConfig`
- expanded `FHyperTwistTrainingCompanionSpeechSessionState`
- contract-library defaults for:
- history/export shell profile ids and definitions
- history/export panel ids and action bindings
- service-health capability exposure
- active companion session-config, service-health, and rolling history/export
shell composition in:
- `UHyperTwistTrainingSubsystem`
- direct speech-client health capability exposure in:
- `UHyperTwistHttpSpeechClient`
- `UHyperTwistMockSpeechClient`
- focused automation coverage in:
- `HyperTwistWhisperCppPhase6RABUsageCostHistoryExportShellContractTest.cpp`
## Why this is still intentionally bounded
This packet lands the operator-facing history/export shell family only.
Still deferred:
- provider receipt review and posted-charge inspection shell surfaces
- actual billing settlement or invoice reconciliation
- actual downloadable model/payload shipping
- real device-permission workflow
- native audio-device route ownership beyond bounded shell posture
- broad assistant-platform scope
## Validation
Build validation:
- `UnrealHyperTwistEditor Win64 Development`
Focused automation validation:
- `HyperTwist.Permissive.WhisperCpp.Phase6R.AB` `3/3`
Regression automation validation:
- `HyperTwist.Permissive.WhisperCpp.Phase6R.AA` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Z` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Y` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.X` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.W` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.V` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.U` `3/3`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.E` `3/3`
- `HyperTwist.Permissive.FasterWhisper.Phase6R.F` `3/3`
- `HyperTwist.Permissive.Piper.Phase6R.G` `3/3`
- `HyperTwist.Permissive.Coqui.Phase6R.H` `3/3`
- `HyperTwist.CleanRoom.CubeDesk` `14/14`
Non-blocking warnings stayed limited to the existing Unreal headless/editor
noise, the pre-existing plugin dependency warning on `UnrealMCP`, and the
known `http:/speech/health` and `http:/vision/health` hostname-resolution
warnings in provider-backed automation.
## Queue effect
This packet consumes the current `Phase 6R-AB` implementation slice.
`ggml-org/whisper.cpp` remains only partially incorporated:
- landed now:
- speech transcript session boundary
- live microphone shell boundary
- device-permission and capture-route readiness shell posture
- downloadable model and payload custody boundary
- first-party provider-profile and BYOK custody boundary
- first-party provider routing and workflow-policy boundary
- first-party normalized usage/cost event-model boundary
- first-party operator-facing provider usage/cost dashboard shell boundary
- first-party provider usage/cost history/export shell boundary for:
- history/export shell profile ids and definitions
- rolling history entry and export issue/state posture
- companion-session history/export composition
- capability exposure for:
- `providerUsageCostHistoryShell`
- `providerUsageCostExportPreview`
- `providerUsageCostSummaryCopy`
- still deferred:
- provider receipt review and posted-charge inspection shell surfaces
- actual billing settlement or invoice reconciliation
- actual downloadable model/payload shipping
- real device-permission workflow
- native audio-device route ownership beyond bounded shell posture
- broad assistant-platform scope
The next clean move is:
- a source-backed `Phase 6R-AC` first-party provider receipt review and
posted-charge inspection preparation/control pass
Keep the future sequencing guards visible:
- first-party HyperTwist
- keep the top-level provider/session contract, routing/policy lane,
usage/cost governance lane, dashboard shell lane, and history/export shell
lane first-party
- `ggml-org/whisper.cpp`
- keep code-license judgments separate from actual model or payload shipping
review in any follow-on packet
- `SYSTRAN/faster-whisper`
- keep the row complementary to the landed provider/session, custody,
routing, usage/cost, dashboard, and history/export seams rather than
widening it into receipt review or billing ownership

View file

@ -0,0 +1,130 @@
# HyperTwist Phase 6R-AB first-party provider usage/cost history/export shell preparation packet
Created on `2026-05-25`
## Status
- first-party HyperTwist packet
- source-backed `Phase 6R-AB` preparation/control slice
## Purpose
This packet scopes the next bounded first-party slice above the landed speech
session, microphone-shell, payload-custody, provider-custody,
provider-routing, normalized usage/cost event, and operator-facing
usage/cost dashboard seams.
The granted slice is:
- first-party provider usage/cost history/export shell only
It is not:
- an actual billing export packet
- an actual settlement or invoice reconciliation packet
- a provider receipt review packet
- an actual payload-shipping packet
- a real device-permission workflow packet
- a native audio-device route ownership packet
- a provider-specific overlay packet
- a broad assistant-platform packet
## Current authority basis
This control pass stands on:
- `docs/ops/HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md`
- `docs/arch/HYPERTWIST_PHASE6R_AA_FIRST_PARTY_OPERATOR_FACING_PROVIDER_USAGE_COST_DASHBOARD_SHELL_IMPLEMENTATION_PACKET_2026-05-25.md`
- `docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md`
The preserved owners do not change here:
- first-party HyperTwist remains the top-level provider/session owner
- first-party HyperTwist remains the usage/cost governance owner
- `ggml-org/whisper.cpp` remains bounded to offline STT donor seams
- `SYSTRAN/faster-whisper` remains bounded to complementary Python
orchestration/service-lane seams
## Granted family
The bounded `Phase 6R-AB` slice may land:
1. first-party usage/cost history/export shell profile ids and definitions
2. rolling history entry, export issue, and shell-state record shapes
3. session-config and companion-session-state expansion for those shapes
4. bounded capability exposure for:
- `providerUsageCostHistoryShell`
- `providerUsageCostExportPreview`
- `providerUsageCostSummaryCopy`
5. focused automation for mock history accumulation and provider-backed
fallback preview posture
The packet must stay out of:
- provider receipt review or posted-charge inspection
- actual billing settlement or invoice reconciliation
- actual payload download or redistribution ownership
- real device-permission workflow ownership
- native audio-device route ownership
- provider-specific export or billing skinning
## Proposed implementation shape
Land the narrower first-party boundary through:
- retained recognition contract types for:
- usage/cost history/export shell profile
- usage/cost history entry
- usage/cost history/export issue
- usage/cost history/export shell state
- expanded speech session config
- expanded companion speech session state
- contract-library defaults for:
- history/export shell profile ids and definitions
- history/export action bindings and panel ids
- service-health capability exposure
- training-subsystem composition for:
- rolling history accumulation
- export preview text posture
- provider-backed fallback issue posture
- estimate-versus-provider-receipt summary posture
- direct speech-client health capability exposure for:
- `providerUsageCostHistoryShell`
- `providerUsageCostExportPreview`
- `providerUsageCostSummaryCopy`
## Validation target
Validate with:
- Unreal build for `UnrealHyperTwistEditor Win64 Development`
- focused automation:
- `HyperTwist.Permissive.WhisperCpp.Phase6R.AB`
- regressions:
- `HyperTwist.Permissive.WhisperCpp.Phase6R.AA`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Z`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.Y`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.X`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.W`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.V`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.U`
- `HyperTwist.Permissive.WhisperCpp.Phase6R.E`
- `HyperTwist.Permissive.FasterWhisper.Phase6R.F`
- `HyperTwist.Permissive.Piper.Phase6R.G`
- `HyperTwist.Permissive.Coqui.Phase6R.H`
- `HyperTwist.CleanRoom.CubeDesk`
## Queue effect
If this packet lands cleanly, the next bounded move becomes:
- a source-backed `Phase 6R-AC` first-party provider receipt review and
posted-charge inspection preparation/control pass
Keep the narrow sequencing guards visible:
- keep actual billing settlement and invoice reconciliation separate from
history/export shell ownership
- keep actual payload shipping separate from usage/cost governance
- keep real device-permission workflow and native capture-route ownership
outside this packet

View file

@ -172,15 +172,19 @@ The next bounded move is now:
dashboard shell control pass is now consumed
28. the bounded first-party `Phase 6R-AA` operator-facing provider usage/cost dashboard shell
packet is now landed in current code
29. the next bounded move is a source-backed `Phase 6R-AB` first-party provider usage/cost
history/export shell preparation/control pass
30. keep the speech-lane guard visible:
29. the generic source-backed `Phase 6R-AB` first-party provider usage/cost history/export
shell control pass is now consumed
30. the bounded first-party `Phase 6R-AB` provider usage/cost history/export shell packet is
now landed in current code
31. the next bounded move is a source-backed `Phase 6R-AC` first-party provider receipt review
and posted-charge inspection preparation/control pass
32. keep the speech-lane guard visible:
- keep code-license judgments separate from model, voice, and payload-license review
31. keep the provider-neutral speech-lane guard visible:
33. keep the provider-neutral speech-lane guard visible:
- first-party HyperTwist owns the top-level provider/session contract
- `whisper.cpp` and `faster-whisper` may win narrower donor slices without inheriting that
lane, the provider routing/policy lane, or the usage/cost governance lane
32. keep the `MagicTile` guard visible:
34. keep the `MagicTile` guard visible:
- keep broad non-Euclidean interaction or WinForms/OpenTK host-shell ownership closed by
default unless a narrower first-party gap is proven above the landed macro-remapping seam

View file

@ -216,8 +216,11 @@ The correct implementation order is:
Current landed ordering status:
- steps `1` through `5` now have bounded first-party implementation anchors
- usage/cost history/export shells and actual billing/settlement remain later
first-party work
- operator-facing usage/cost history/export shells now also have a bounded
first-party implementation anchor
- provider receipt review and posted-charge inspection remain the next bounded
first-party gap above the landed history/export shell
- actual billing/settlement remains later first-party work
- provider-specific adapters remain later work
Do not invert that order.

View file

@ -127,6 +127,7 @@ Do not collapse those three tiers into one undifferentiated "features" voice.
| First-party provider routing and workflow-policy boundary | Implemented now | landed first-party `Phase 6R-Y` | First-party routing-policy ids/definitions, route-decision summaries, fallback-health posture, and workflow-policy capability exposure are now live above the landed provider-custody seam. |
| First-party normalized usage/cost event surface | Implemented now | landed first-party `Phase 6R-Z` | First-party accounting-profile definitions, normalized usage/cost event templates and health summaries, quota/rate-limit state, and bounded capability exposure are now live above the landed provider-routing seam. |
| First-party operator-facing provider usage/cost dashboard shell | Implemented now | landed first-party `Phase 6R-AA` | First-party dashboard shell profiles, dashboard issue/state objects, quota escalation banners, route diagnostics, and operator-facing panel/action contracts are now live above the landed normalized usage/cost seam. |
| First-party provider usage/cost history/export shell | Implemented now | landed first-party `Phase 6R-AB` | First-party rolling history entries, export issue/state objects, summary export preview/copy posture, and operator-facing panel/action contracts are now live above the landed provider usage/cost dashboard seam. |
| Analytics/reporting surfaces | Implemented now | landed analytics/reporting packets | Reporting is real, but bounded to accepted retained slices. |
| Browser/spatial/media adjunct surfaces | Implemented now | landed `three.js`, `react-three-fiber`, `xr`, `model-viewer`, `remotion` packets | These are implemented bounded families, not proof of unlimited browser-shell parity. |
@ -223,6 +224,7 @@ repo.
| First-party provider routing and workflow-policy boundary | Implemented now | landed first-party `Phase 6R-Y` packet | Current bounded routing-policy ids/definitions, route-decision summaries, explicit fallback-health posture, and workflow-policy capability exposure above the landed provider/session and provider-custody seams. |
| First-party normalized usage/cost event surface | Implemented now | landed first-party `Phase 6R-Z` packet | Current bounded accounting-profile ids/definitions, normalized usage/cost event summaries, quota/rate-limit state, and bounded capability exposure above the landed provider-routing seam. |
| First-party operator-facing provider usage/cost dashboard shell | Implemented now | landed first-party `Phase 6R-AA` packet | Current bounded dashboard shell profile ids/definitions, dashboard issue/state posture, and capability exposure above the landed normalized usage/cost seam. |
| First-party provider usage/cost history/export shell | Implemented now | landed first-party `Phase 6R-AB` packet | Current bounded history/export shell profile ids/definitions, rolling history entry and export issue/state posture, summary export preview/copy behavior, and capability exposure above the landed provider usage/cost dashboard seam. |
| OpenAI-compatible custom endpoint support | Deep-source grounded retained | doctrine-defined first-party target | First-class target is now represented in the landed custody model, but full routing/runtime support is still deferred. |
| Provider-specific overlays | Shallow placeholder | future provider-family work only | Keep internal until source-grounded and normalized. |

View file

@ -171,8 +171,12 @@ Canonical discovery surfaces for roadmap interpretation:
dashboard shell control pass is now consumed
- the bounded first-party `Phase 6R-AA` operator-facing provider usage/cost dashboard shell
packet is now landed in current code
- the current next bounded move is a source-backed `Phase 6R-AB` first-party provider
usage/cost history/export shell preparation/control pass, while keeping actual billing,
- the generic source-backed `Phase 6R-AB` first-party provider usage/cost history/export shell
control pass is now consumed
- the bounded first-party `Phase 6R-AB` provider usage/cost history/export shell packet is now
landed in current code
- the current next bounded move is a source-backed `Phase 6R-AC` first-party provider receipt
review and posted-charge inspection preparation/control pass, while keeping actual billing,
settlement, real device-permission workflow, native capture-route ownership, and actual
payload shipping separately deferred
- the repo-row implementation queue is now live from that `Phase 6R-A` entry point rather than
@ -261,14 +265,15 @@ Current routing truth:
- `brianpeiris/RiftSketch`
- the v6.3 CSV label `not_live_reference_or_discard_candidate` is not the final state by itself; read the closed `0R-E` packet for the retained-versus-discarded split
The next bounded move is a source-backed `Phase 6R-AB` first-party provider
usage/cost history/export shell preparation/control pass.
The next bounded move is a source-backed `Phase 6R-AC` first-party provider
receipt review and posted-charge inspection preparation/control pass.
Queue interpretation after that control pass:
- then continue with the retained repo-row queue
- highest current repo-row queue pressure sits in:
- the first-party provider usage/cost history/export shell remainder above
- the first-party provider receipt review and posted-charge inspection shell
remainder above
the partially landed `whisper.cpp` and `faster-whisper` speech seams
- `HactarCE/Hyperspeedcube` is now closed for the currently justified retained row:
- landed:
@ -359,6 +364,7 @@ Queue interpretation after that control pass:
- first-party provider-profile and BYOK custody boundary
- first-party provider routing and policy boundary
- first-party normalized usage/cost event-model boundary
- first-party provider usage/cost history/export shell boundary
- bounded shell capability exposure for:
- microphone capture shell
- device-permission shell
@ -373,8 +379,12 @@ Queue interpretation after that control pass:
- normalized cost events
- quota/rate-limit state
- operator-facing provider usage/cost dashboard shell
- provider usage/cost history shell
- provider usage/cost export preview
- provider usage/cost summary copy
- still deferred:
- provider usage/cost history/export shell surfaces
- provider receipt review and posted-charge inspection shell surfaces
- actual billing settlement or invoice reconciliation
- real device-permission workflow
- native capture-route ownership beyond bounded shell posture
- actual downloadable model or payload shipping
@ -422,13 +432,15 @@ Queue interpretation after that control pass:
- viseme / gesture runtime integration
- broad assistant-platform scope
- the next queue shape is now:
- first-party provider usage/cost history/export shell assessment above the landed speech
session, shell, payload-custody, provider-custody, provider-routing, normalized usage/cost,
and operator-facing dashboard seams
- first-party provider receipt review and posted-charge inspection shell
assessment above the landed speech session, shell, payload-custody,
provider-custody, provider-routing, normalized usage/cost, operator-facing
dashboard, and history/export seams
- the next bounded move should stay narrow:
- a source-backed `Phase 6R-AB` control pass before any widening into actual billing
settlement, actual payload shipping, real device-permission workflow, broad voice-output
ownership, or broad assistant-platform scope
- a source-backed `Phase 6R-AC` control pass before any widening into actual
billing settlement, invoice reconciliation, actual payload shipping, real
device-permission workflow, broad voice-output ownership, or broad
assistant-platform scope
- keep the speech-input / voice sidecar legal sequencing guard visible:
- keep code-license judgments separate from model, voice, and payload-license review
- keep the provider-neutral speech-lane guard visible: