From 7a8182cb2c05e3cbb34d4db6bf422f287f8a28ec Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Sun, 24 May 2026 23:00:02 +0200 Subject: [PATCH] Implement Phase 6R-X provider profile BYOK custody --- .../HyperTwistContractLibrary.cpp | 128 ++++++++++ .../HyperTwistHttpSpeechClient.cpp | 50 ++++ .../HyperTwistTrainingSubsystem.cpp | 213 ++++++++++++++++ .../HyperTwistRecognitionTypes.h | 213 ++++++++++++++++ ...hase6RXProviderProfileByokContractTest.cpp | 234 ++++++++++++++++++ docs/REPO_LICENSE_TRACKING.md | 18 +- ...USTODY_IMPLEMENTATION_PACKET_2026-05-24.md | 176 +++++++++++++ ...K_CUSTODY_PREPARATION_PACKET_2026-05-24.md | 178 +++++++++++++ ...PERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md | 17 +- .../HyperTwist/FEATURE_REGISTRY.md | 5 +- .../HyperTwist/ROADMAP.md | 33 ++- 11 files changed, 1238 insertions(+), 27 deletions(-) create mode 100644 UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistWhisperCppPhase6RXProviderProfileByokContractTest.cpp create mode 100644 docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_IMPLEMENTATION_PACKET_2026-05-24.md create mode 100644 docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_PREPARATION_PACKET_2026-05-24.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp index 2788d46..354d887 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp @@ -955,6 +955,112 @@ namespace HyperTwistContractLibraryInternal return Profile; } + TArray MakeDefaultSpeechProviderModelIds() + { + return { + TEXT("speech-model/whisper.cpp/base.en"), + TEXT("speech-vad/whisper.cpp/silero-v6.2.0") + }; + } + + TArray MakeDefaultSpeechProviderCapabilityFlags() + { + return { + TEXT("transcribe"), + TEXT("vadSegments"), + TEXT("grammarHints"), + TEXT("microphoneCaptureShell"), + TEXT("devicePermissionShell"), + TEXT("captureRouteReadinessShell"), + TEXT("captureRouteRetry"), + TEXT("streamingPreview"), + TEXT("manualTranscriptCommit"), + TEXT("batchedTranscribe"), + TEXT("wordTimestamps"), + TEXT("languageDetection"), + TEXT("promptHints") + }; + } + + FHyperTwistSpeechProviderProfile MakeMockSpeechProviderProfile() + { + FHyperTwistSpeechProviderProfile Profile; + Profile.ProviderProfileId = TEXT("speech-provider/mock-offline-profile-v1"); + Profile.DisplayLabel = TEXT("Mock Offline Speech"); + Profile.ProviderClass = TEXT("first-party-mock-provider"); + Profile.EndpointClass = TEXT("in-process-mock"); + Profile.EndpointReferenceId = TEXT("speech/provider-profile/mock-offline"); + Profile.EndpointBaseUrl = TEXT("in-process://mock"); + Profile.AuthMaterialSource = TEXT("not-required"); + Profile.AuthReferenceId.Reset(); + Profile.ModelSelectionMode = TEXT("per-profile-model-map"); + Profile.SupportedModelIds = MakeDefaultSpeechProviderModelIds(); + Profile.CapabilityFlags = MakeDefaultSpeechProviderCapabilityFlags(); + Profile.bEnabled = true; + Profile.bUserLabeled = false; + Profile.bSupportsEnableDisable = true; + Profile.bSupportsCustomBaseUrl = false; + Profile.bPreservesFirstPartyCustody = true; + return Profile; + } + + FHyperTwistSpeechProviderProfile MakeLocalHttpSpeechProviderProfile( + const FString& ProviderLabel, + const FString& ServiceEndpoint + ) + { + FHyperTwistSpeechProviderProfile Profile; + Profile.ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1"); + Profile.DisplayLabel = ProviderLabel.IsEmpty() ? TEXT("Local HTTP Speech Sidecar") : ProviderLabel; + Profile.ProviderClass = TEXT("bounded-speech-sidecar-service"); + Profile.EndpointClass = TEXT("local-self-hosted-http"); + Profile.EndpointReferenceId = TEXT("speech/provider-profile/local-http-sidecar"); + Profile.EndpointBaseUrl = ServiceEndpoint; + Profile.AuthMaterialSource = TEXT("first-party-out-of-band-secret-reference"); + Profile.AuthReferenceId = TEXT("speech/byok/local-http-sidecar/default"); + Profile.ModelSelectionMode = TEXT("per-profile-model-map"); + Profile.SupportedModelIds = MakeDefaultSpeechProviderModelIds(); + Profile.CapabilityFlags = MakeDefaultSpeechProviderCapabilityFlags(); + Profile.bEnabled = true; + Profile.bUserLabeled = true; + Profile.bSupportsEnableDisable = true; + Profile.bSupportsCustomBaseUrl = true; + Profile.bPreservesFirstPartyCustody = true; + return Profile; + } + + FHyperTwistSpeechByokCustodyProfile MakeDefaultSpeechByokCustodyProfile(const FString& ProfileId) + { + FHyperTwistSpeechByokCustodyProfile Profile; + Profile.ByokCustodyProfileId = ProfileId; + Profile.KeyCustodyPosture = TEXT("first-party-user-supplied"); + Profile.EndpointCustodyPosture = TEXT("first-party-custom-endpoint-owned"); + Profile.SecretStoragePosture = TEXT("out-of-band-secret-reference-only"); + Profile.ProfileLabelingPosture = TEXT("user-labeled-byok-profile-supported"); + Profile.EnablementPosture = TEXT("per-profile-enable-disable-supported"); + Profile.SupportedProviderClasses = { + TEXT("official-direct-provider"), + TEXT("openai-compatible-custom-endpoint"), + TEXT("byok-endpoint"), + TEXT("managed-gateway-provider"), + TEXT("local-self-hosted-provider"), + TEXT("bounded-speech-sidecar-service") + }; + Profile.bSupportsOfficialProviderProfiles = true; + Profile.bSupportsOpenAiCompatibleCustomEndpoints = true; + Profile.bSupportsManagedGatewayProfiles = true; + Profile.bSupportsLocalSelfHostedProfiles = true; + Profile.bSupportsBoundedSidecarProfiles = true; + Profile.bSupportsUserLabeledProfiles = true; + Profile.bSupportsPerProfileModelMaps = true; + Profile.bSupportsPerProfileAuthMaterial = true; + Profile.bSupportsEnableDisableControls = true; + Profile.bStoresSecretsOutOfBand = true; + Profile.bPreservesProviderNeutrality = true; + Profile.bAllowsDonorOwnedKeyCustody = false; + return Profile; + } + TArray MakeDefaultSpeechModelPayloads() { return { @@ -1735,6 +1841,17 @@ FHyperTwistSpeechSessionConfig UHyperTwistContractLibrary::MakeSampleSpeechSessi HyperTwistContractLibraryInternal::MakeDefaultCoachCommandMicrophoneShellProfile( Config.MicrophoneShellProfileId ); + Config.ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1"); + Config.ProviderProfileDefinition = + HyperTwistContractLibraryInternal::MakeLocalHttpSpeechProviderProfile( + TEXT("Local HTTP Speech Sidecar"), + TEXT("http://127.0.0.1:8766") + ); + Config.ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + Config.ByokCustodyProfileDefinition = + HyperTwistContractLibraryInternal::MakeDefaultSpeechByokCustodyProfile( + Config.ByokCustodyProfileId + ); Config.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1"); Config.PayloadCustodyProfileDefinition = HyperTwistContractLibraryInternal::MakeDefaultSpeechPayloadCustodyProfile( @@ -1831,12 +1948,23 @@ FHyperTwistSpeechServiceHealth UHyperTwistContractLibrary::MakeMockSpeechService TEXT("wordTimestamps"), TEXT("languageDetection"), TEXT("promptHints"), + TEXT("providerProfileCustody"), + TEXT("byokCustody"), + TEXT("openAiCompatibleCustomEndpointProfile"), + TEXT("userLabeledByokProfiles"), TEXT("downloadableModelPayloadCustody"), TEXT("payloadIntegrityReview") }; Health.SupportedOrchestrationProfiles = { TEXT("python-batch-transcribe-v1") }; + Health.ProviderProfileId = TEXT("speech-provider/mock-offline-profile-v1"); + Health.ProviderProfileDefinition = HyperTwistContractLibraryInternal::MakeMockSpeechProviderProfile(); + Health.ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + Health.ByokCustodyProfileDefinition = + HyperTwistContractLibraryInternal::MakeDefaultSpeechByokCustodyProfile( + Health.ByokCustodyProfileId + ); Health.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1"); Health.PayloadCustodyProfileDefinition = HyperTwistContractLibraryInternal::MakeDefaultSpeechPayloadCustodyProfile( diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistRecognition/HyperTwistHttpSpeechClient.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistRecognition/HyperTwistHttpSpeechClient.cpp index 403d3f7..339effb 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistRecognition/HyperTwistHttpSpeechClient.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistRecognition/HyperTwistHttpSpeechClient.cpp @@ -308,6 +308,8 @@ bool UHyperTwistHttpSpeechClient::CloseSpeechSession(const FString& SessionId, F FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHealth() const { FHyperTwistSpeechServiceHealth Health = UHyperTwistContractLibrary::MakeMockSpeechServiceHealth(); + const FHyperTwistSpeechSessionConfig ProviderDefaults = + UHyperTwistContractLibrary::MakeSampleSpeechSessionConfig(); Health.ProviderLabel = ProviderLabel; Health.ServiceVersion = TEXT("provider-unavailable/v1"); Health.ServiceEndpoint = ServiceBaseUrl; @@ -328,6 +330,10 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal TEXT("wordTimestamps"), TEXT("languageDetection"), TEXT("promptHints"), + TEXT("providerProfileCustody"), + TEXT("byokCustody"), + TEXT("openAiCompatibleCustomEndpointProfile"), + TEXT("userLabeledByokProfiles"), TEXT("downloadableModelPayloadCustody"), TEXT("payloadIntegrityReview") }; @@ -344,6 +350,14 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal Response)) { LastTransportError = Response.Error; + Health.ProviderProfileId = ProviderDefaults.ProviderProfileId; + Health.ProviderProfileDefinition = ProviderDefaults.ProviderProfileDefinition; + Health.ProviderProfileDefinition.DisplayLabel = ProviderLabel.IsEmpty() + ? Health.ProviderProfileDefinition.DisplayLabel + : ProviderLabel; + Health.ProviderProfileDefinition.EndpointBaseUrl = ServiceBaseUrl; + Health.ByokCustodyProfileId = ProviderDefaults.ByokCustodyProfileId; + Health.ByokCustodyProfileDefinition = ProviderDefaults.ByokCustodyProfileDefinition; Health.LastError = LastTransportError; return Health; } @@ -372,12 +386,24 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal TEXT("wordTimestamps"), TEXT("languageDetection"), TEXT("promptHints"), + TEXT("providerProfileCustody"), + TEXT("byokCustody"), + TEXT("openAiCompatibleCustomEndpointProfile"), + TEXT("userLabeledByokProfiles"), TEXT("downloadableModelPayloadCustody"), TEXT("payloadIntegrityReview") }; Health.SupportedOrchestrationProfiles = { TEXT("python-batch-transcribe-v1") }; + Health.ProviderProfileId = ProviderDefaults.ProviderProfileId; + Health.ProviderProfileDefinition = ProviderDefaults.ProviderProfileDefinition; + Health.ProviderProfileDefinition.DisplayLabel = ProviderLabel.IsEmpty() + ? Health.ProviderProfileDefinition.DisplayLabel + : ProviderLabel; + Health.ProviderProfileDefinition.EndpointBaseUrl = ServiceBaseUrl; + Health.ByokCustodyProfileId = ProviderDefaults.ByokCustodyProfileId; + Health.ByokCustodyProfileDefinition = ProviderDefaults.ByokCustodyProfileDefinition; Health.LastError = LastTransportError; return Health; } @@ -404,9 +430,33 @@ FHyperTwistSpeechServiceHealth UHyperTwistHttpSpeechClient::GetSpeechServiceHeal Health.Capabilities.AddUnique(TEXT("wordTimestamps")); Health.Capabilities.AddUnique(TEXT("languageDetection")); Health.Capabilities.AddUnique(TEXT("promptHints")); + Health.Capabilities.AddUnique(TEXT("providerProfileCustody")); + Health.Capabilities.AddUnique(TEXT("byokCustody")); + Health.Capabilities.AddUnique(TEXT("openAiCompatibleCustomEndpointProfile")); + Health.Capabilities.AddUnique(TEXT("userLabeledByokProfiles")); Health.Capabilities.AddUnique(TEXT("downloadableModelPayloadCustody")); Health.Capabilities.AddUnique(TEXT("payloadIntegrityReview")); Health.SupportedOrchestrationProfiles.AddUnique(TEXT("python-batch-transcribe-v1")); + if (Health.ProviderProfileId.IsEmpty()) + { + Health.ProviderProfileId = ProviderDefaults.ProviderProfileId; + } + if (!Health.ProviderProfileDefinition.IsStructurallyValid()) + { + Health.ProviderProfileDefinition = ProviderDefaults.ProviderProfileDefinition; + } + Health.ProviderProfileDefinition.DisplayLabel = ProviderLabel.IsEmpty() + ? Health.ProviderProfileDefinition.DisplayLabel + : ProviderLabel; + Health.ProviderProfileDefinition.EndpointBaseUrl = ServiceBaseUrl; + if (Health.ByokCustodyProfileId.IsEmpty()) + { + Health.ByokCustodyProfileId = ProviderDefaults.ByokCustodyProfileId; + } + if (!Health.ByokCustodyProfileDefinition.IsStructurallyValid()) + { + Health.ByokCustodyProfileDefinition = ProviderDefaults.ByokCustodyProfileDefinition; + } if (Health.PayloadCustodyProfileId.IsEmpty()) { Health.PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1"); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp index ce4da20..fcd8b42 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp @@ -3030,6 +3030,112 @@ namespace HyperTwistTrainingSubsystemInternal return Profile; } + TArray BuildDefaultSpeechProviderModelIds() + { + return { + TEXT("speech-model/whisper.cpp/base.en"), + TEXT("speech-vad/whisper.cpp/silero-v6.2.0") + }; + } + + TArray BuildDefaultSpeechProviderCapabilityFlags() + { + return { + TEXT("transcribe"), + TEXT("vadSegments"), + TEXT("grammarHints"), + TEXT("microphoneCaptureShell"), + TEXT("devicePermissionShell"), + TEXT("captureRouteReadinessShell"), + TEXT("captureRouteRetry"), + TEXT("streamingPreview"), + TEXT("manualTranscriptCommit"), + TEXT("batchedTranscribe"), + TEXT("wordTimestamps"), + TEXT("languageDetection"), + TEXT("promptHints") + }; + } + + FHyperTwistSpeechProviderProfile BuildDefaultMockSpeechProviderProfile() + { + FHyperTwistSpeechProviderProfile Profile; + Profile.ProviderProfileId = TEXT("speech-provider/mock-offline-profile-v1"); + Profile.DisplayLabel = TEXT("Mock Offline Speech"); + Profile.ProviderClass = TEXT("first-party-mock-provider"); + Profile.EndpointClass = TEXT("in-process-mock"); + Profile.EndpointReferenceId = TEXT("speech/provider-profile/mock-offline"); + Profile.EndpointBaseUrl = TEXT("in-process://mock"); + Profile.AuthMaterialSource = TEXT("not-required"); + Profile.AuthReferenceId.Reset(); + Profile.ModelSelectionMode = TEXT("per-profile-model-map"); + Profile.SupportedModelIds = BuildDefaultSpeechProviderModelIds(); + Profile.CapabilityFlags = BuildDefaultSpeechProviderCapabilityFlags(); + Profile.bEnabled = true; + Profile.bUserLabeled = false; + Profile.bSupportsEnableDisable = true; + Profile.bSupportsCustomBaseUrl = false; + Profile.bPreservesFirstPartyCustody = true; + return Profile; + } + + FHyperTwistSpeechProviderProfile BuildDefaultHttpSpeechProviderProfile( + const FString& ProviderLabel, + const FString& ServiceEndpoint + ) + { + FHyperTwistSpeechProviderProfile Profile; + Profile.ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1"); + Profile.DisplayLabel = ProviderLabel.IsEmpty() ? TEXT("Local HTTP Speech Sidecar") : ProviderLabel; + Profile.ProviderClass = TEXT("bounded-speech-sidecar-service"); + Profile.EndpointClass = TEXT("local-self-hosted-http"); + Profile.EndpointReferenceId = TEXT("speech/provider-profile/local-http-sidecar"); + Profile.EndpointBaseUrl = ServiceEndpoint; + Profile.AuthMaterialSource = TEXT("first-party-out-of-band-secret-reference"); + Profile.AuthReferenceId = TEXT("speech/byok/local-http-sidecar/default"); + Profile.ModelSelectionMode = TEXT("per-profile-model-map"); + Profile.SupportedModelIds = BuildDefaultSpeechProviderModelIds(); + Profile.CapabilityFlags = BuildDefaultSpeechProviderCapabilityFlags(); + Profile.bEnabled = true; + Profile.bUserLabeled = true; + Profile.bSupportsEnableDisable = true; + Profile.bSupportsCustomBaseUrl = true; + Profile.bPreservesFirstPartyCustody = true; + return Profile; + } + + FHyperTwistSpeechByokCustodyProfile BuildDefaultSpeechByokCustodyProfile(const FString& ProfileId) + { + FHyperTwistSpeechByokCustodyProfile Profile; + Profile.ByokCustodyProfileId = ProfileId; + Profile.KeyCustodyPosture = TEXT("first-party-user-supplied"); + Profile.EndpointCustodyPosture = TEXT("first-party-custom-endpoint-owned"); + Profile.SecretStoragePosture = TEXT("out-of-band-secret-reference-only"); + Profile.ProfileLabelingPosture = TEXT("user-labeled-byok-profile-supported"); + Profile.EnablementPosture = TEXT("per-profile-enable-disable-supported"); + Profile.SupportedProviderClasses = { + TEXT("official-direct-provider"), + TEXT("openai-compatible-custom-endpoint"), + TEXT("byok-endpoint"), + TEXT("managed-gateway-provider"), + TEXT("local-self-hosted-provider"), + TEXT("bounded-speech-sidecar-service") + }; + Profile.bSupportsOfficialProviderProfiles = true; + Profile.bSupportsOpenAiCompatibleCustomEndpoints = true; + Profile.bSupportsManagedGatewayProfiles = true; + Profile.bSupportsLocalSelfHostedProfiles = true; + Profile.bSupportsBoundedSidecarProfiles = true; + Profile.bSupportsUserLabeledProfiles = true; + Profile.bSupportsPerProfileModelMaps = true; + Profile.bSupportsPerProfileAuthMaterial = true; + Profile.bSupportsEnableDisableControls = true; + Profile.bStoresSecretsOutOfBand = true; + Profile.bPreservesProviderNeutrality = true; + Profile.bAllowsDonorOwnedKeyCustody = false; + return Profile; + } + TArray BuildDefaultSpeechModelPayloads() { return { @@ -3064,6 +3170,49 @@ namespace HyperTwistTrainingSubsystemInternal }; } + void ApplySpeechProviderProfileDefaults( + FHyperTwistSpeechSessionConfig& SessionConfig, + const bool bUseMockClient + ) + { + if (SessionConfig.ProviderProfileId.IsEmpty() + && SessionConfig.ProviderProfileDefinition.IsStructurallyValid()) + { + SessionConfig.ProviderProfileId = SessionConfig.ProviderProfileDefinition.ProviderProfileId; + } + if (SessionConfig.ProviderProfileId.IsEmpty()) + { + SessionConfig.ProviderProfileId = bUseMockClient + ? TEXT("speech-provider/mock-offline-profile-v1") + : TEXT("speech-provider/local-http-sidecar-profile-v1"); + } + if (!SessionConfig.ProviderProfileDefinition.IsStructurallyValid()) + { + SessionConfig.ProviderProfileDefinition = bUseMockClient + ? BuildDefaultMockSpeechProviderProfile() + : BuildDefaultHttpSpeechProviderProfile( + TEXT("Local HTTP Speech Sidecar"), + TEXT("http://127.0.0.1:8766") + ); + } + SessionConfig.ProviderProfileId = SessionConfig.ProviderProfileDefinition.ProviderProfileId; + if (SessionConfig.ByokCustodyProfileId.IsEmpty() + && SessionConfig.ByokCustodyProfileDefinition.IsStructurallyValid()) + { + SessionConfig.ByokCustodyProfileId = SessionConfig.ByokCustodyProfileDefinition.ByokCustodyProfileId; + } + if (SessionConfig.ByokCustodyProfileId.IsEmpty()) + { + SessionConfig.ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + } + if (!SessionConfig.ByokCustodyProfileDefinition.IsStructurallyValid()) + { + SessionConfig.ByokCustodyProfileDefinition = + BuildDefaultSpeechByokCustodyProfile(SessionConfig.ByokCustodyProfileId); + } + SessionConfig.ByokCustodyProfileId = SessionConfig.ByokCustodyProfileDefinition.ByokCustodyProfileId; + } + void ApplySpeechPayloadCustodyDefaults(FHyperTwistSpeechSessionConfig& SessionConfig) { if (SessionConfig.PayloadCustodyProfileId.IsEmpty()) @@ -3081,6 +3230,53 @@ namespace HyperTwistTrainingSubsystemInternal } } + void ApplySpeechProviderProfileHealthDefaults( + FHyperTwistSpeechServiceHealth& Health, + const bool bUseProviderBackedClient + ) + { + if (Health.ProviderProfileId.IsEmpty() + && Health.ProviderProfileDefinition.IsStructurallyValid()) + { + Health.ProviderProfileId = Health.ProviderProfileDefinition.ProviderProfileId; + } + if (Health.ProviderProfileId.IsEmpty()) + { + Health.ProviderProfileId = bUseProviderBackedClient + ? TEXT("speech-provider/local-http-sidecar-profile-v1") + : TEXT("speech-provider/mock-offline-profile-v1"); + } + if (!Health.ProviderProfileDefinition.IsStructurallyValid()) + { + Health.ProviderProfileDefinition = bUseProviderBackedClient + ? BuildDefaultHttpSpeechProviderProfile( + Health.ProviderLabel, + Health.ServiceEndpoint + ) + : BuildDefaultMockSpeechProviderProfile(); + } + Health.ProviderProfileId = Health.ProviderProfileDefinition.ProviderProfileId; + if (Health.ByokCustodyProfileId.IsEmpty() + && Health.ByokCustodyProfileDefinition.IsStructurallyValid()) + { + Health.ByokCustodyProfileId = Health.ByokCustodyProfileDefinition.ByokCustodyProfileId; + } + if (Health.ByokCustodyProfileId.IsEmpty()) + { + Health.ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + } + if (!Health.ByokCustodyProfileDefinition.IsStructurallyValid()) + { + Health.ByokCustodyProfileDefinition = + BuildDefaultSpeechByokCustodyProfile(Health.ByokCustodyProfileId); + } + Health.ByokCustodyProfileId = Health.ByokCustodyProfileDefinition.ByokCustodyProfileId; + Health.Capabilities.AddUnique(TEXT("providerProfileCustody")); + Health.Capabilities.AddUnique(TEXT("byokCustody")); + Health.Capabilities.AddUnique(TEXT("openAiCompatibleCustomEndpointProfile")); + Health.Capabilities.AddUnique(TEXT("userLabeledByokProfiles")); + } + void ApplySpeechPayloadCustodyHealthDefaults(FHyperTwistSpeechServiceHealth& Health) { if (Health.PayloadCustodyProfileId.IsEmpty()) @@ -9543,9 +9739,14 @@ FHyperTwistVisionSessionConfig UHyperTwistTrainingSubsystem::BuildActiveRecognit FHyperTwistSpeechSessionConfig UHyperTwistTrainingSubsystem::BuildActiveCompanionSpeechSessionConfig() const { FHyperTwistSpeechSessionConfig SessionConfig = ActiveCompanionSpeechSessionState.SessionConfig; + const bool bUseMockClient = CompanionSpeechClientKind.Equals(TEXT("mock"), ESearchCase::IgnoreCase); if (!HasActiveRun()) { HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyDefaults(SessionConfig); + HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileDefaults( + SessionConfig, + bUseMockClient + ); return SessionConfig; } @@ -9663,6 +9864,10 @@ FHyperTwistSpeechSessionConfig UHyperTwistTrainingSubsystem::BuildActiveCompanio } SessionConfig.bEnableWordTimestamps = SessionConfig.OrchestrationProfile.bEnableWordTimestamps; HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyDefaults(SessionConfig); + HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileDefaults( + SessionConfig, + bUseMockClient + ); return SessionConfig; } @@ -9738,6 +9943,10 @@ void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth() : TEXT("in-process://mock"); ActiveCompanionSpeechSessionState.ServiceHealth.bReady = false; ActiveCompanionSpeechSessionState.ServiceHealth.LastError = TEXT("speech-client-unavailable"); + HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileHealthDefaults( + ActiveCompanionSpeechSessionState.ServiceHealth, + ActiveCompanionSpeechSessionState.bUsingProviderBackedClient + ); HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyHealthDefaults( ActiveCompanionSpeechSessionState.ServiceHealth ); @@ -9748,6 +9957,10 @@ void UHyperTwistTrainingSubsystem::RefreshCompanionSpeechServiceHealth() } ActiveCompanionSpeechSessionState.ServiceHealth = SpeechClient->GetSpeechServiceHealth(); + HyperTwistTrainingSubsystemInternal::ApplySpeechProviderProfileHealthDefaults( + ActiveCompanionSpeechSessionState.ServiceHealth, + ActiveCompanionSpeechSessionState.bUsingProviderBackedClient + ); HyperTwistTrainingSubsystemInternal::ApplySpeechPayloadCustodyHealthDefaults( ActiveCompanionSpeechSessionState.ServiceHealth ); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistRecognition/HyperTwistRecognitionTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistRecognition/HyperTwistRecognitionTypes.h index 64d484b..dbe7af3 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistRecognition/HyperTwistRecognitionTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistRecognition/HyperTwistRecognitionTypes.h @@ -1923,6 +1923,187 @@ struct FHyperTwistSpeechPayloadCustodyProfile } }; +USTRUCT(BlueprintType) +struct FHyperTwistSpeechProviderProfile +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DisplayLabel = TEXT("Local Speech Sidecar"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ProviderClass = TEXT("bounded-speech-sidecar-service"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EndpointClass = TEXT("local-self-hosted-http"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EndpointReferenceId = TEXT("speech/provider-profile/local-http-sidecar"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EndpointBaseUrl = TEXT("http://127.0.0.1:8766"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString AuthMaterialSource = TEXT("first-party-out-of-band-secret-reference"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString AuthReferenceId = TEXT("speech/byok/local-http-sidecar/default"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ModelSelectionMode = TEXT("per-profile-model-map"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray SupportedModelIds; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray CapabilityFlags; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bEnabled = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bUserLabeled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsEnableDisable = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsCustomBaseUrl = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bPreservesFirstPartyCustody = true; + + bool IsStructurallyValid() const + { + if (ProviderProfileId.IsEmpty() + || DisplayLabel.IsEmpty() + || ProviderClass.IsEmpty() + || EndpointClass.IsEmpty() + || EndpointReferenceId.IsEmpty() + || AuthMaterialSource.IsEmpty() + || ModelSelectionMode.IsEmpty() + || SupportedModelIds.Num() <= 0 + || CapabilityFlags.Num() <= 0) + { + return false; + } + + if (!AuthMaterialSource.Equals(TEXT("not-required"), ESearchCase::CaseSensitive) + && AuthReferenceId.IsEmpty()) + { + return false; + } + + for (const FString& ModelId : SupportedModelIds) + { + if (ModelId.IsEmpty()) + { + return false; + } + } + + for (const FString& CapabilityFlag : CapabilityFlags) + { + if (CapabilityFlag.IsEmpty()) + { + return false; + } + } + + return true; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistSpeechByokCustodyProfile +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString KeyCustodyPosture = TEXT("first-party-user-supplied"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EndpointCustodyPosture = TEXT("first-party-custom-endpoint-owned"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SecretStoragePosture = TEXT("out-of-band-secret-reference-only"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ProfileLabelingPosture = TEXT("user-labeled-byok-profile-supported"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EnablementPosture = TEXT("per-profile-enable-disable-supported"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray SupportedProviderClasses; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsOfficialProviderProfiles = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsOpenAiCompatibleCustomEndpoints = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsManagedGatewayProfiles = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsLocalSelfHostedProfiles = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsBoundedSidecarProfiles = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsUserLabeledProfiles = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsPerProfileModelMaps = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsPerProfileAuthMaterial = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bSupportsEnableDisableControls = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bStoresSecretsOutOfBand = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bPreservesProviderNeutrality = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bAllowsDonorOwnedKeyCustody = false; + + bool IsStructurallyValid() const + { + if (ByokCustodyProfileId.IsEmpty() + || KeyCustodyPosture.IsEmpty() + || EndpointCustodyPosture.IsEmpty() + || SecretStoragePosture.IsEmpty() + || ProfileLabelingPosture.IsEmpty() + || EnablementPosture.IsEmpty() + || SupportedProviderClasses.Num() <= 0) + { + return false; + } + + for (const FString& ProviderClassId : SupportedProviderClasses) + { + if (ProviderClassId.IsEmpty()) + { + return false; + } + } + + return true; + } +}; + USTRUCT(BlueprintType) struct FHyperTwistSpeechSessionConfig { @@ -1961,6 +2142,18 @@ struct FHyperTwistSpeechSessionConfig UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") FHyperTwistSpeechMicrophoneShellProfile MicrophoneShellProfileDefinition; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FHyperTwistSpeechProviderProfile ProviderProfileDefinition; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FHyperTwistSpeechByokCustodyProfile ByokCustodyProfileDefinition; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") FString PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1"); @@ -1996,6 +2189,10 @@ struct FHyperTwistSpeechSessionConfig || TaskKind.IsEmpty() || MicrophoneShellProfileId.IsEmpty() || !MicrophoneShellProfileDefinition.IsStructurallyValid() + || ProviderProfileId.IsEmpty() + || !ProviderProfileDefinition.IsStructurallyValid() + || ByokCustodyProfileId.IsEmpty() + || !ByokCustodyProfileDefinition.IsStructurallyValid() || PayloadCustodyProfileId.IsEmpty() || !PayloadCustodyProfileDefinition.IsStructurallyValid() || RequiredModelPayloads.Num() <= 0 @@ -2224,6 +2421,18 @@ struct FHyperTwistSpeechServiceHealth UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") TArray SupportedOrchestrationProfiles; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ProviderProfileId = TEXT("speech-provider/local-http-sidecar-profile-v1"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FHyperTwistSpeechProviderProfile ProviderProfileDefinition; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ByokCustodyProfileId = TEXT("speech-byok-custody-profile-v1"); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FHyperTwistSpeechByokCustodyProfile ByokCustodyProfileDefinition; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") FString PayloadCustodyProfileId = TEXT("downloadable-model-payload-custody-v1"); @@ -2246,6 +2455,10 @@ struct FHyperTwistSpeechServiceHealth { if (ProviderLabel.IsEmpty() || ServiceVersion.IsEmpty() + || ProviderProfileId.IsEmpty() + || !ProviderProfileDefinition.IsStructurallyValid() + || ByokCustodyProfileId.IsEmpty() + || !ByokCustodyProfileDefinition.IsStructurallyValid() || PayloadCustodyProfileId.IsEmpty() || !PayloadCustodyProfileDefinition.IsStructurallyValid()) { diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistWhisperCppPhase6RXProviderProfileByokContractTest.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistWhisperCppPhase6RXProviderProfileByokContractTest.cpp new file mode 100644 index 0000000..f7fc4ee --- /dev/null +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistWhisperCppPhase6RXProviderProfileByokContractTest.cpp @@ -0,0 +1,234 @@ +// 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 HyperTwistWhisperCppPhase6RXTestInternal +{ + FHyperTwistTrainingDeck MakeSpeechDeck() + { + FHyperTwistTrainingDeck Deck; + Deck.DeckId = TEXT("phase6r-x/provider-profile-byok"); + Deck.Title = TEXT("Phase 6R-X Provider Profile And BYOK"); + Deck.DeliveryModes = { + EHyperTwistTrainingDeliveryMode::CoachReviewed + }; + + FHyperTwistTrainingCase TrainingCase; + TrainingCase.CaseId = TEXT("phase6r-x-case"); + TrainingCase.PuzzleId = TEXT("cube/3x3x3"); + TrainingCase.PromptKind = EHyperTwistTrainingPromptKind::Sequence; + TrainingCase.PromptLabel = TEXT("Phase 6R-X 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( + UHyperTwistTrainingSubsystem::StaticClass(), + TEXT("CompanionSpeechClientKind") + )) + { + SpeechClientKindProperty->SetPropertyValue_InContainer(TrainingSubsystem, ClientKind); + } + } + + UHyperTwistTrainingSubsystem* MakeSpeechSubsystem(const FString& SessionId, const FString& ClientKind) + { + UGameInstance* GameInstance = NewObject(GetTransientPackage()); + if (GameInstance == nullptr) + { + return nullptr; + } + + UHyperTwistTrainingSubsystem* TrainingSubsystem = NewObject(GameInstance); + if (TrainingSubsystem == nullptr) + { + return nullptr; + } + + ForceSpeechClientKind(TrainingSubsystem, ClientKind); + const FHyperTwistTrainingRunState RunState = TrainingSubsystem->StartTrainingRunFromDeck( + MakeSpeechDeck(), + TEXT("phase6r-x-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( + UHyperTwistTrainingSubsystem::StaticClass(), + TEXT("ActiveCompanionSpeechClientObject") + )) + { + return Cast( + ClientProperty->GetObjectPropertyValue_InContainer(TrainingSubsystem) + ); + } + + return nullptr; + } +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistWhisperCppPhase6RXProviderProfileSessionConfigTest, + "HyperTwist.Permissive.WhisperCpp.Phase6R.X.ProviderProfileSessionConfig", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistWhisperCppPhase6RXProviderProfileSessionConfigTest::RunTest(const FString& Parameters) +{ + UHyperTwistTrainingSubsystem* TrainingSubsystem = + HyperTwistWhisperCppPhase6RXTestInternal::MakeSpeechSubsystem( + TEXT("phase6r-x-config-session"), + TEXT("mock") + ); + TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-X."), TrainingSubsystem); + if (TrainingSubsystem == nullptr) + { + return false; + } + + FString OpenError; + TestTrue(TEXT("The provider-profile route must open a speech session."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError)); + TestTrue(TEXT("Opening the provider-profile speech session must not report an error."), OpenError.IsEmpty()); + + const FHyperTwistSpeechSessionConfig& Config = + TrainingSubsystem->GetActiveCompanionSpeechSessionState().SessionConfig; + + TestTrue(TEXT("The provider-profile session config must remain structurally valid."), Config.IsStructurallyValid()); + TestEqual(TEXT("The mock route must preserve the mock provider profile id."), Config.ProviderProfileId, TEXT("speech-provider/mock-offline-profile-v1")); + TestTrue(TEXT("The provider-profile session config must expose a structurally valid provider profile."), Config.ProviderProfileDefinition.IsStructurallyValid()); + TestEqual(TEXT("The mock route must preserve the mock provider class."), Config.ProviderProfileDefinition.ProviderClass, TEXT("first-party-mock-provider")); + TestEqual(TEXT("The mock route must preserve the in-process endpoint class."), Config.ProviderProfileDefinition.EndpointClass, TEXT("in-process-mock")); + TestEqual(TEXT("The mock route must preserve the no-auth provider posture."), Config.ProviderProfileDefinition.AuthMaterialSource, TEXT("not-required")); + TestEqual(TEXT("The provider profile must expose two supported model ids."), Config.ProviderProfileDefinition.SupportedModelIds.Num(), 2); + TestTrue(TEXT("The provider profile must expose the manual transcript capability in its capability map."), Config.ProviderProfileDefinition.CapabilityFlags.Contains(TEXT("manualTranscriptCommit"))); + + TestEqual(TEXT("The session config must preserve the BYOK custody profile id."), Config.ByokCustodyProfileId, TEXT("speech-byok-custody-profile-v1")); + TestTrue(TEXT("The session config must expose a structurally valid BYOK custody profile."), Config.ByokCustodyProfileDefinition.IsStructurallyValid()); + TestTrue(TEXT("The BYOK custody profile must preserve OpenAI-compatible custom endpoint support."), Config.ByokCustodyProfileDefinition.bSupportsOpenAiCompatibleCustomEndpoints); + TestTrue(TEXT("The BYOK custody profile must preserve user-labeled provider profile support."), Config.ByokCustodyProfileDefinition.bSupportsUserLabeledProfiles); + TestTrue(TEXT("The BYOK custody profile must preserve the bounded sidecar provider class."), Config.ByokCustodyProfileDefinition.SupportedProviderClasses.Contains(TEXT("bounded-speech-sidecar-service"))); + TestFalse(TEXT("The BYOK custody profile must not allow donor-owned key custody."), Config.ByokCustodyProfileDefinition.bAllowsDonorOwnedKeyCustody); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistWhisperCppPhase6RXProviderProfileServiceHealthTest, + "HyperTwist.Permissive.WhisperCpp.Phase6R.X.ProviderProfileServiceHealth", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistWhisperCppPhase6RXProviderProfileServiceHealthTest::RunTest(const FString& Parameters) +{ + UHyperTwistTrainingSubsystem* TrainingSubsystem = + HyperTwistWhisperCppPhase6RXTestInternal::MakeSpeechSubsystem( + TEXT("phase6r-x-health-session"), + TEXT("mock") + ); + TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-X."), TrainingSubsystem); + if (TrainingSubsystem == nullptr) + { + return false; + } + + FString OpenError; + TestTrue(TEXT("The provider-profile route must open a speech session."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError)); + TestTrue(TEXT("Opening the provider-profile speech session must not report an error."), OpenError.IsEmpty()); + + const FHyperTwistSpeechServiceHealth& Health = + TrainingSubsystem->GetActiveCompanionSpeechSessionState().ServiceHealth; + + TestTrue(TEXT("The provider-profile service health must remain structurally valid."), Health.IsStructurallyValid()); + TestEqual(TEXT("The service health must preserve the active provider profile id."), Health.ProviderProfileId, TEXT("speech-provider/mock-offline-profile-v1")); + TestTrue(TEXT("The service health must preserve the provider-profile custody capability."), Health.Capabilities.Contains(TEXT("providerProfileCustody"))); + TestTrue(TEXT("The service health must preserve the BYOK custody capability."), Health.Capabilities.Contains(TEXT("byokCustody"))); + TestTrue(TEXT("The service health must preserve the OpenAI-compatible endpoint profile capability."), Health.Capabilities.Contains(TEXT("openAiCompatibleCustomEndpointProfile"))); + TestTrue(TEXT("The service health must preserve the user-labeled BYOK profile capability."), Health.Capabilities.Contains(TEXT("userLabeledByokProfiles"))); + TestTrue(TEXT("The service health must expose a structurally valid BYOK custody profile."), Health.ByokCustodyProfileDefinition.IsStructurallyValid()); + TestTrue(TEXT("The BYOK custody profile must preserve per-profile model maps."), Health.ByokCustodyProfileDefinition.bSupportsPerProfileModelMaps); + TestTrue(TEXT("The BYOK custody profile must preserve per-profile auth material."), Health.ByokCustodyProfileDefinition.bSupportsPerProfileAuthMaterial); + TestTrue(TEXT("The BYOK custody profile must preserve profile enable-disable controls."), Health.ByokCustodyProfileDefinition.bSupportsEnableDisableControls); + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistWhisperCppPhase6RXProviderBackedByokFallbackTest, + "HyperTwist.Permissive.WhisperCpp.Phase6R.X.ProviderBackedByokFallback", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistWhisperCppPhase6RXProviderBackedByokFallbackTest::RunTest(const FString& Parameters) +{ + UHyperTwistTrainingSubsystem* TrainingSubsystem = + HyperTwistWhisperCppPhase6RXTestInternal::MakeSpeechSubsystem( + TEXT("phase6r-x-provider-session"), + TEXT("http-sidecar") + ); + TestNotNull(TEXT("The speech subsystem must be constructed for Phase 6R-X."), TrainingSubsystem); + if (TrainingSubsystem == nullptr) + { + return false; + } + + UHyperTwistHttpSpeechClient* HttpSpeechClient = + HyperTwistWhisperCppPhase6RXTestInternal::ResolveHttpSpeechClient(TrainingSubsystem); + TestNotNull(TEXT("The provider-backed speech client must be available for the BYOK fallback test."), HttpSpeechClient); + if (HttpSpeechClient == nullptr) + { + return false; + } + + HttpSpeechClient->ServiceBaseUrl.Reset(); + + FString OpenError; + TestFalse(TEXT("The provider-backed provider-profile route must fail cleanly when no provider endpoint is configured."), TrainingSubsystem->OpenActiveCompanionSpeechSession(OpenError)); + TestEqual(TEXT("The provider-backed provider-profile route must report the missing service base URL."), OpenError, TEXT("service-base-url-missing")); + + const FHyperTwistTrainingCompanionSpeechSessionState SessionState = + TrainingSubsystem->GetActiveCompanionSpeechSessionState(); + const FHyperTwistSpeechServiceHealth& Health = SessionState.ServiceHealth; + + TestTrue(TEXT("The provider-backed fallback health must remain structurally valid."), Health.IsStructurallyValid()); + TestEqual(TEXT("The provider-backed fallback must keep the local HTTP provider profile id."), Health.ProviderProfileId, TEXT("speech-provider/local-http-sidecar-profile-v1")); + TestEqual(TEXT("The provider-backed fallback must keep the local self-hosted endpoint class."), Health.ProviderProfileDefinition.EndpointClass, TEXT("local-self-hosted-http")); + TestEqual(TEXT("The provider-backed fallback must keep the first-party auth custody posture."), Health.ProviderProfileDefinition.AuthMaterialSource, TEXT("first-party-out-of-band-secret-reference")); + TestTrue(TEXT("The provider-backed fallback must preserve custom base URL support."), Health.ProviderProfileDefinition.bSupportsCustomBaseUrl); + TestFalse(TEXT("The provider-backed fallback must keep the endpoint base URL empty when the configured route is empty."), !Health.ProviderProfileDefinition.EndpointBaseUrl.IsEmpty()); + TestFalse(TEXT("The provider-backed fallback must not drop the provider endpoint reference id."), Health.ProviderProfileDefinition.EndpointReferenceId.IsEmpty()); + TestEqual(TEXT("The provider-backed fallback must keep the BYOK custody profile id."), Health.ByokCustodyProfileId, TEXT("speech-byok-custody-profile-v1")); + TestTrue(TEXT("The provider-backed fallback must preserve provider-profile custody capability."), Health.Capabilities.Contains(TEXT("providerProfileCustody"))); + TestTrue(TEXT("The provider-backed fallback must preserve BYOK custody capability."), Health.Capabilities.Contains(TEXT("byokCustody"))); + TestTrue(TEXT("The provider-backed fallback must preserve OpenAI-compatible custom endpoint support."), Health.ByokCustodyProfileDefinition.bSupportsOpenAiCompatibleCustomEndpoints); + TestEqual(TEXT("The provider-backed fallback must keep the route error in the shell state."), SessionState.MicrophoneShellState.LastRouteError, TEXT("service-base-url-missing")); + return true; +} + +#endif diff --git a/docs/REPO_LICENSE_TRACKING.md b/docs/REPO_LICENSE_TRACKING.md index d8ed6b0..b93f2be 100644 --- a/docs/REPO_LICENSE_TRACKING.md +++ b/docs/REPO_LICENSE_TRACKING.md @@ -179,8 +179,12 @@ Status update on `2026-05-21`: payload custody control pass is now consumed - the bounded permissive `Phase 6R-W` `ggml-org/whisper.cpp` downloadable model and payload custody packet is now landed in current code -- the current next bounded move is a source-backed `Phase 6R-X` first-party provider-profile - and BYOK custody preparation/control pass, not a new restrictive packet by default +- the generic source-backed `Phase 6R-X` first-party provider-profile and BYOK custody control + pass is now consumed +- the bounded first-party `Phase 6R-X` provider-profile and BYOK custody packet is now landed in + current code +- the current next bounded move is a source-backed `Phase 6R-Y` first-party provider routing and + policy 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 @@ -284,8 +288,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-X` first-party provider-profile and - BYOK custody preparation/control pass +- the next bounded move is a source-backed `Phase 6R-Y` first-party provider routing and policy + preparation/control pass Companion docs: @@ -1539,11 +1543,13 @@ Approved working posture: capture-route readiness shell posture above the existing microphone shell seam - the next bounded permissive implementation slice is now landed as downloadable model and payload custody metadata above the existing transcript-session and shell seams +- the next bounded first-party implementation slice is now landed as provider-profile and BYOK + custody metadata above the existing transcript-session, shell, and payload-custody seams - the top-level provider/session contract remains first-party HyperTwist-owned and provider-neutral; this row does not own that lane - keep real device-permission workflow, native capture-route ownership, actual payload shipping, - provider-profile and BYOK custody, and future voice-asset review separate from the - code-license judgment + first-party provider routing and policy, normalized usage/cost events, and future voice-asset + review separate from the code-license judgment - treat `SYSTRAN/faster-whisper` as the landed complementary Python-orchestration donor rather than widening `whisper.cpp` into the runtime core diff --git a/docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_IMPLEMENTATION_PACKET_2026-05-24.md b/docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_IMPLEMENTATION_PACKET_2026-05-24.md new file mode 100644 index 0000000..b50655e --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_IMPLEMENTATION_PACKET_2026-05-24.md @@ -0,0 +1,176 @@ +# HyperTwist Phase 6R-X first-party provider profile and BYOK custody implementation packet + +Created on `2026-05-24` + +## Status + +- first-party HyperTwist packet +- bounded permissive `Phase 6R-X` implementation slice + +## Purpose + +This packet lands the next narrower bounded slice above the retained +`ggml-org/whisper.cpp` and `SYSTRAN/faster-whisper` speech-input seams. + +The landed slice is: + +- first-party provider-profile and BYOK custody metadata above the existing + speech session, microphone-shell, permission/readiness, and payload-custody + seams + +It is not: + +- a full donor-row transplant +- an actual downloadable payload-shipping packet +- a routing/policy layer packet +- a normalized usage/cost event-model packet +- a real device-permission workflow packet +- a native audio-device route ownership packet +- a top-level provider/session contract packet +- a voice-output packet +- a broad assistant-platform packet + +## Current authority basis + +This implementation packet stands on: + +- `docs/REPO_LICENSE_TRACKING.md` +- `docs/ops/HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md` +- `docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_PREPARATION_PACKET_2026-05-24.md` + +The top-level provider/session contract owner does not change here: + +- first-party HyperTwist remains the provider-neutral owner for the speech + provider/session lane +- first-party HyperTwist now lands the first bounded provider-profile and + BYOK custody boundary for that lane +- `ggml-org/whisper.cpp` remains bounded to retained offline STT donor seams +- `SYSTRAN/faster-whisper` remains bounded to complementary Python + orchestration/service-lane seams + +The granted family remains bounded to: + +- explicit provider-profile contract shaping +- explicit BYOK custody contract shaping +- per-profile model-map and capability-map wording +- out-of-band auth-reference wording +- bounded speech-health capability exposure for the narrower provider-custody + seam + +This packet lands only the next narrower family in that granted set. + +## Landed scope + +The current code now owns a retained provider-profile / BYOK custody contract +through: + +- retained recognition contract types for: + - `FHyperTwistSpeechProviderProfile` + - `FHyperTwistSpeechByokCustodyProfile` + - expanded `FHyperTwistSpeechSessionConfig` + - expanded `FHyperTwistSpeechServiceHealth` +- sample session-config and service-health outputs in: + - `UHyperTwistContractLibrary` +- direct-donor speech client seam capability exposure in: + - `UHyperTwistHttpSpeechClient` +- active companion session-config and service-health normalization in: + - `UHyperTwistTrainingSubsystem` +- focused automation coverage in: + - `HyperTwistWhisperCppPhase6RXProviderProfileByokContractTest.cpp` + +## Why this is still intentionally bounded + +This packet lands the next first-party provider-custody seam, but it does not +widen into neighboring retained families. + +Still deferred: + +- first-party provider routing and policy +- normalized usage/cost events +- actual downloadable payload shipping +- real device-permission workflow +- native audio-device route ownership beyond bounded shell posture +- voice-output ownership +- broad assistant-platform scope + +## Validation + +Build validation: + +- `C:\Program Files\Epic Games\UE_5.7\Engine\Build\BatchFiles\Build.bat UnrealHyperTwistEditor Win64 Development -Project='C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.uproject' -WaitMutex -NoHotReloadFromIDE -NoUba` + +Focused automation validation: + +- `C:\Program Files\Epic Games\UE_5.7\Engine\Binaries\Win64\UnrealEditor-Cmd.exe C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.uproject -unattended -nop4 -nosplash -NullRHI -log -stdout -FullStdOutLogOutput -AbsLog=C:\HyperTwist\UnrealHyperTwist\Saved\Logs\Phase6R-X-ProviderProfileByok-Verify.log -ReportExportPath=C:\HyperTwist\UnrealHyperTwist\Saved\AutomationReports\Phase6R-X-ProviderProfileByok-Verify -ExecCmds="Automation RunTests HyperTwist.Permissive.WhisperCpp.Phase6R.X; Quit" -TestExit="Automation Test Queue Empty"` + +Regression automation validation: + +- `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` + +Expected covered tests: + +- `ProviderProfileSessionConfig` +- `ProviderProfileServiceHealth` +- `ProviderBackedByokFallback` +- existing `Phase 6R-W`, `Phase 6R-V`, `Phase 6R-U`, `Phase 6R-E`, + `Phase 6R-F`, `Phase 6R-G`, `Phase 6R-H`, and `CubeDesk` regression suites + +## Queue effect + +This packet consumes the current `Phase 6R-X` implementation slice. + +`ggml-org/whisper.cpp` remains only partially incorporated: + +- landed now: + - speech transcript session boundary + - VAD-aware session config and utterance envelope + - transcript segment and transcript result + - sidecar health and speech client boundary + - live microphone shell profile and shell-state boundary + - device-permission and capture-route readiness shell posture + - downloadable model and payload custody boundary + - first-party provider-profile and BYOK custody boundary for: + - provider-profile ids and definitions + - BYOK custody ids and definitions + - supported provider-class wording + - per-profile model / capability maps + - out-of-band auth-reference wording + - capability exposure for: + - `providerProfileCustody` + - `byokCustody` + - `openAiCompatibleCustomEndpointProfile` + - `userLabeledByokProfiles` +- still deferred: + - first-party provider routing and policy + - normalized usage/cost events + - actual downloadable 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-Y` first-party provider routing and policy + preparation/control pass + +Keep the future sequencing guards visible: + +- first-party HyperTwist + - keep the top-level provider/session contract and provider routing/policy + lane first-party + - keep normalized usage/cost events separate from the landed provider-profile + and BYOK custody boundary +- `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 shell, payload-custody, and + provider-profile seams and bounded to Python orchestration/service-lane + ownership rather than provider routing ownership diff --git a/docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_PREPARATION_PACKET_2026-05-24.md b/docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_PREPARATION_PACKET_2026-05-24.md new file mode 100644 index 0000000..fade3ad --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_PREPARATION_PACKET_2026-05-24.md @@ -0,0 +1,178 @@ +# HyperTwist Phase 6R-X first-party provider profile and BYOK custody preparation packet + +Created on `2026-05-24` + +## Status + +- historical same-day preparation authority +- bounded post-`Phase 6R-W` control slice +- the first bounded implementation slice now lands separately under: + - `docs/arch/HYPERTWIST_PHASE6R_X_FIRST_PARTY_PROVIDER_PROFILE_AND_BYOK_CUSTODY_IMPLEMENTATION_PACKET_2026-05-24.md` + +## Purpose + +This packet freezes the next widening order after the landed `Phase 6R-W` +`whisper.cpp` downloadable model and payload custody slice. + +The open task was: + +- define the next bounded source-backed widening packet above the landed speech + session, shell, and payload-custody seams as the retained `Phase 6R-X` + first-party provider-profile and BYOK custody seam + +It is not: + +- a full `whisper.cpp` row transplant +- an actual downloadable payload shipping packet +- a routing/policy layer packet +- a normalized usage/cost event-model packet +- a real device-permission workflow packet +- a native audio-device route ownership packet +- a voice-output packet +- a broad assistant-platform packet + +## Current authority basis + +This preparation packet stands on already-closed authority: + +- `docs/REPO_LICENSE_TRACKING.md` +- `docs/ops/HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md` +- `docs/arch/HYPERTWIST_PHASE6R_W_WHISPER_CPP_DOWNLOADABLE_MODEL_AND_PAYLOAD_CUSTODY_IMPLEMENTATION_PACKET_2026-05-24.md` + +The key accepted routing facts are: + +- first-party HyperTwist already owns the top-level provider/session contract +- the landed `Phase 6R-W` packet already owns payload-custody metadata above + the current speech seams +- the correct next implementation order is now: + - provider-profile and BYOK custody surfaces + - then routing/policy + - then normalized usage/cost events +- the retained donor value strongest for the next narrow widening is: + - first-party provider-profile ids and definitions + - first-party BYOK custody ids and definitions + - per-profile model lists or capability maps + - auth-reference wording that preserves out-of-band secret custody + - session-config and service-health exposure for the bounded custody seam +- ownership denied here is: + - do not widen into routing/policy ownership + - do not widen into actual downloadable payload shipping + - do not widen into normalized usage/cost event ownership + - do not widen into real device-permission workflow ownership + - do not let `whisper.cpp` or `faster-whisper` inherit the top-level + provider/session or provider-profile lane + +## Required result + +The source-backed control pass for this packet is now complete. + +The first actual `6R-X` implementation packet should: + +- define one bounded first-party provider-profile and BYOK custody slice above + the landed speech session, shell, and payload-custody seams +- land first-party provider-profile ids/definitions for explicit provider + class, endpoint class, model-map, capability-map, and auth-reference wording +- land first-party BYOK custody ids/definitions for explicit supported-provider + class, user-label, enable/disable, and out-of-band secret-custody wording +- sync those surfaces into active speech session-config composition and mock / + HTTP speech service-health composition +- add bounded capability exposure and focused automation +- explicitly state which neighboring retained families stay closed + +## Source-backed retained basis + +Inspected retained / doctrine basis: + +- `C:\visual_studio_solutions\multi_project\GPT 5.4 HyperTwist parse\49-ggml-org-whisper-cpp-upstream-dossier.md` +- `C:\visual_studio_solutions\multi_project\GPT 5.4 HyperTwist parse\50-systran-faster-whisper-upstream-dossier.md` +- `C:\HyperTwist\docs\ops\HYPERTWIST_PROVIDER_NEUTRALITY_AND_BYOK_DOCTRINE_2026-05-21.md` +- `C:\Workspaces\HyperTwist\mirrors\permissive\ggml-org\whisper.cpp\README.md` +- `C:\Workspaces\HyperTwist\mirrors\permissive\SYSTRAN\faster-whisper\README.md` + +Inspected first-party receiving basis: + +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistRecognition/HyperTwistRecognitionTypes.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistRecognition/HyperTwistSpeechClient.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSubsystem.h` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistRecognition/HyperTwistMockSpeechClient.cpp` +- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistRecognition/HyperTwistHttpSpeechClient.cpp` + +## Narrowed 6R-X slice decision + +The next widening slice is fixed as: + +1. first-party provider-profile and BYOK custody metadata + +That narrowed slice covers: + +- first-party speech contract expansion for: + - provider-profile ids + - provider-profile definitions + - BYOK custody ids + - BYOK custody definitions + - supported provider-class wording + - per-profile model maps + - per-profile capability maps + - auth-reference wording that keeps secrets out-of-band + - per-profile enable/disable wording +- lifecycle sync for: + - active session-config composition + - mock and HTTP service-health exposure + - provider-backed fallback health posture +- bounded capability exposure for: + - `providerProfileCustody` + - `byokCustody` + - `openAiCompatibleCustomEndpointProfile` + - `userLabeledByokProfiles` +- focused automation coverage + +## Deferred neighboring families + +The first `6R-X` implementation packet must keep these capability families +closed: + +- first-party provider routing and policy ownership +- normalized usage/cost event ownership +- actual downloadable payload shipping +- real device-permission workflow ownership +- native audio-device route ownership beyond bounded shell posture +- voice-output ownership +- broad assistant-platform scope + +## Acceptance criteria + +- the packet records why the queue advanced from landed `Phase 6R-W` to + `Phase 6R-X` +- the packet records that the first `6R-X` widening slice is first-party + provider-profile and BYOK custody metadata only +- the packet states exact out-of-scope families for the first `6R-X` pass +- the packet preserves first-party provider-neutrality and out-of-band secret + custody explicitly +- the packet leaves routing/policy and normalized usage/cost widening deferred + +## Validation checklist + +1. confirm the landed `Phase 6R-W` packet is the consumed prior queue head +2. confirm the retained speech seam narrows cleanly to first-party + provider-profile and BYOK custody metadata rather than routing/policy or + payload-shipping ownership +3. confirm the next implementation packet is framed as bounded first-party + widening rather than a broad provider-platform transplant + +That is the packet. + +## Queue effect + +This preparation packet is now consumed by the landed bounded `Phase 6R-X` +implementation slice. + +Once that slice lands, the next clean move should stay narrow inside the +first-party provider lane at: + +- a source-backed `Phase 6R-Y` first-party provider routing and policy + preparation/control pass, while keeping normalized usage/cost events, actual + payload shipping, and real device workflow ownership separately deferred diff --git a/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md b/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md index 9ad24c4..5156db2 100644 --- a/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md +++ b/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md @@ -128,14 +128,19 @@ The next bounded move is now: payload custody control pass is now consumed 20. the bounded permissive `Phase 6R-W` `ggml-org/whisper.cpp` downloadable model and payload custody packet is now landed in current code -21. the next bounded move is a source-backed `Phase 6R-X` first-party provider-profile and - BYOK custody preparation/control pass -22. keep the speech-lane guard visible: +21. the generic source-backed `Phase 6R-X` first-party provider-profile and BYOK custody + control pass is now consumed +22. the bounded first-party `Phase 6R-X` provider-profile and BYOK custody packet is now + landed in current code +23. the next bounded move is a source-backed `Phase 6R-Y` first-party provider routing and + policy preparation/control pass +24. keep the speech-lane guard visible: - keep code-license judgments separate from model, voice, and payload-license review -23. keep the provider-neutral speech-lane guard visible: +25. 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 -24. keep the `MagicTile` guard visible: + - `whisper.cpp` and `faster-whisper` may win narrower donor slices without inheriting that + lane or the provider routing/policy lane +26. 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 diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md b/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md index 1ab9839..5793777 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md @@ -123,6 +123,7 @@ Do not collapse those three tiers into one undifferentiated "features" voice. | Live microphone capture shell | Implemented now | landed `whisper.cpp` `Phase 6R-U` | First-party microphone shell profile, bounded panel/action contract, and live shell-state composition are now live above the transcript-session seam. | | Device-permission and capture-route readiness shell | Implemented now | landed `whisper.cpp` `Phase 6R-V` | First-party permission/readiness shell posture, issue objects, retry/request semantics, and bounded capability exposure are now live above the microphone shell seam. | | Downloadable model and payload custody boundary | Implemented now | landed `whisper.cpp` `Phase 6R-W` | First-party payload-custody profile, required/supported model-payload descriptors, and bounded integrity metadata are now live above the landed speech session and shell seams. | +| First-party provider profile and BYOK custody boundary | Implemented now | landed first-party `Phase 6R-X` | First-party provider-profile definitions, BYOK custody definitions, per-profile model/capability maps, and out-of-band auth-reference wording are now live above the landed speech session, shell, and payload-custody seams. | | 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. | @@ -215,8 +216,8 @@ repo. | Feature | Status | Primary authority | Notes | |---|---|---|---| | First-party provider-neutral speech/vision contract | Implemented now | first-party recognition/speech client seams | Current bounded provider/session truth. | -| Provider-neutral BYOK/profile model | Deep-source grounded retained | doctrine-defined first-party target | Not yet fully realized in code. | -| OpenAI-compatible custom endpoint support | Deep-source grounded retained | doctrine-defined first-party target | First-class target, not yet fully realized in code. | +| Provider-neutral BYOK/profile custody boundary | Implemented now | landed first-party `Phase 6R-X` packet | Current bounded provider-profile ids/definitions, BYOK custody ids/definitions, per-profile model/capability maps, and out-of-band auth-reference wording. | +| 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. | | Normalized usage/cost/routing surface | Deep-source grounded retained | doctrine-defined first-party target | Retained governance target, not live product truth yet. | | Provider-specific overlays | Shallow placeholder | future provider-family work only | Keep internal until source-grounded and normalized. | diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md index 6d61912..60080c9 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md @@ -155,9 +155,14 @@ Canonical discovery surfaces for roadmap interpretation: payload custody control pass is now consumed - the bounded permissive `Phase 6R-W` `ggml-org/whisper.cpp` downloadable model and payload custody packet is now landed in current code -- the current next bounded move is a source-backed `Phase 6R-X` first-party provider-profile - and BYOK custody preparation/control pass, while keeping real device-permission workflow, - native capture-route ownership, and actual payload shipping separately deferred +- the generic source-backed `Phase 6R-X` first-party provider-profile and BYOK custody control + pass is now consumed +- the bounded first-party `Phase 6R-X` provider-profile and BYOK custody packet is now landed in + current code +- the current next bounded move is a source-backed `Phase 6R-Y` first-party provider routing and + policy preparation/control pass, while keeping normalized usage/cost events, 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 waiting on another first-party packet @@ -219,14 +224,14 @@ Current routing truth: - active non-live implementation-board rows: `34` - retained benchmark, oracle, or clean-room-later rows outside the active implementation board: `9` -The next bounded move is a source-backed `Phase 6R-X` first-party -provider-profile and BYOK custody preparation/control pass. +The next bounded move is a source-backed `Phase 6R-Y` first-party +provider routing and policy 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-profile and BYOK custody remainder above the + - the first-party provider routing and policy remainder above the partially landed `whisper.cpp` and `faster-whisper` speech seams - `HactarCE/Hyperspeedcube` is now closed for the currently justified retained row: - landed: @@ -314,6 +319,7 @@ Queue interpretation after that control pass: - live microphone shell profile and shell-state boundary - device-permission and capture-route readiness shell posture - downloadable model and payload custody boundary + - first-party provider-profile and BYOK custody boundary - bounded shell capability exposure for: - microphone capture shell - device-permission shell @@ -322,10 +328,11 @@ Queue interpretation after that control pass: - streaming preview - manual transcript commit - still deferred: + - first-party provider routing and policy + - normalized usage/cost event model - real device-permission workflow - native capture-route ownership beyond bounded shell posture - actual downloadable model or payload shipping - - provider-profile and BYOK custody - broad assistant-platform scope - `SYSTRAN/faster-whisper` is now landed as a partially incorporated row rather than a generic future placeholder: @@ -336,7 +343,6 @@ Queue interpretation after that control pass: - still deferred: - richer live service-lane batching, prompt-routing, or retrieval tuning beyond the landed bounded profile - - provider-profile and BYOK custody - downloadable model or payload shipping - TTS or voice-output ownership - broad assistant-platform scope @@ -371,17 +377,18 @@ Queue interpretation after that control pass: - viseme / gesture runtime integration - broad assistant-platform scope - the next queue shape is now: - - first-party provider-profile and BYOK custody assessment above the landed - speech session, shell, and payload-custody seams + - first-party provider routing and policy assessment above the landed speech session, shell, + payload-custody, and provider-custody seams - the next bounded move should stay narrow: - - a source-backed `Phase 6R-X` control pass before any widening into actual - payload shipping, real device-permission workflow, broad voice-output + - a source-backed `Phase 6R-Y` control pass before any widening into normalized usage/cost + events, 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: - first-party HyperTwist owns the top-level provider/session contract - - `whisper.cpp` and `faster-whisper` may win narrower donor slices without inheriting that lane + - first-party HyperTwist owns the provider routing/policy lane + - `whisper.cpp` and `faster-whisper` may win narrower donor slices without inheriting either lane - keep the voice-output guard visible: - `coqui-ai/TTS` stays bounded to advanced narration orchestration metadata rather than broad voice-platform ownership