From f01fa43af6e930033021250d4da93ebcd6f48530 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Thu, 28 May 2026 22:24:39 +0200 Subject: [PATCH] Implement Phase S1-B skill settings menu and off-state control --- .../HyperTwistContractLibrary.cpp | 54 +++ .../HyperTwistSkillCoreLibrary.cpp | 248 +++++++++++- .../HyperTwistContractLibrary.h | 17 + .../HyperTwistSkillCoreLibrary.h | 6 + .../HyperTwistSkills/HyperTwistSkillTypes.h | 378 ++++++++++++++++++ ...PhaseS1BSettingsVisibilityContractTest.cpp | 276 +++++++++++++ ...ONTROL_IMPLEMENTATION_PACKET_2026-05-28.md | 109 +++++ ...E_CONTROL_PREPARATION_PACKET_2026-05-28.md | 101 +++++ ...PERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md | 7 +- ...AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md | 14 +- .../HyperTwist/ARCHITECTURE.md | 4 +- .../HyperTwist/FEATURE_REGISTRY.md | 2 +- .../HyperTwist/PROVENANCE_AND_TRUST_MODEL.md | 2 + .../HyperTwist/ROADMAP.md | 6 +- .../HyperTwist/SKILLS.md | 11 +- 15 files changed, 1219 insertions(+), 16 deletions(-) create mode 100644 UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistSkillPhaseS1BSettingsVisibilityContractTest.cpp create mode 100644 docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_IMPLEMENTATION_PACKET_2026-05-28.md create mode 100644 docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_PREPARATION_PACKET_2026-05-28.md diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp index 4cf076b..b550370 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp @@ -26,6 +26,24 @@ namespace HyperTwistContractLibraryInternal return FJsonObjectConverter::JsonObjectStringToUStruct(Json, &OutValue, 0, 0); } + FHyperTwistSkillControlProfile MakeSampleSkillControlProfile(const bool bMasterEnabled) + { + FHyperTwistSkillControlProfile ControlProfile; + ControlProfile.ProfileId = bMasterEnabled + ? TEXT("skill-controls/default") + : TEXT("skill-controls/all-skills-off"); + ControlProfile.DisplayLabel = bMasterEnabled + ? TEXT("Default Skill Controls") + : TEXT("All Skills Off"); + ControlProfile.bMasterEnabled = bMasterEnabled; + ControlProfile.bDurableSettingsExposed = true; + ControlProfile.bImmediateMenuControlExposed = true; + ControlProfile.Summary = bMasterEnabled + ? TEXT("Default first-party skill control profile.") + : TEXT("Control profile proving the core product remains valid with all skills off."); + return ControlProfile; + } + FHyperTwistCoachSessionQueueSummary MakeSampleCoachSessionQueueSummaryManual() { FHyperTwistCoachSessionQueueSummary QueueSummary; @@ -3915,6 +3933,22 @@ FHyperTwistSkillRegistryState UHyperTwistContractLibrary::MakeSampleSkillRegistr return UHyperTwistSkillCoreLibrary::DeriveSkillRegistryState(); } +FHyperTwistSkillControlState UHyperTwistContractLibrary::MakeSampleSkillControlState() +{ + return UHyperTwistSkillCoreLibrary::DeriveSkillControlState( + MakeSampleSkillRegistryState(), + HyperTwistContractLibraryInternal::MakeSampleSkillControlProfile(true) + ); +} + +FHyperTwistSkillControlState UHyperTwistContractLibrary::MakeAllSkillsOffSkillControlState() +{ + return UHyperTwistSkillCoreLibrary::DeriveSkillControlState( + MakeSampleSkillRegistryState(), + HyperTwistContractLibraryInternal::MakeSampleSkillControlProfile(false) + ); +} + FHyperTwistTrainingRepositoryIntegrityReport UHyperTwistContractLibrary::MakeSampleTrainingRepositoryIntegrityReport() { FHyperTwistTrainingRepositoryState RepositoryState = MakeSampleTrainingRepositoryState(); @@ -5033,6 +5067,15 @@ FString UHyperTwistContractLibrary::SerializeSkillRegistryStateToJson( ); } +FString UHyperTwistContractLibrary::SerializeSkillControlStateToJson( + const FHyperTwistSkillControlState& SkillControlState +) +{ + return HyperTwistContractLibraryInternal::SerializeStructToJson( + SkillControlState + ); +} + FString UHyperTwistContractLibrary::SerializeTrainingTimerExportPacketToJson( const FHyperTwistTrainingTimerExportPacket& TimerExportPacket ) @@ -5166,6 +5209,17 @@ bool UHyperTwistContractLibrary::DeserializeSkillRegistryStateFromJson( ); } +bool UHyperTwistContractLibrary::DeserializeSkillControlStateFromJson( + const FString& Json, + FHyperTwistSkillControlState& OutSkillControlState +) +{ + return HyperTwistContractLibraryInternal::DeserializeStructFromJson( + Json, + OutSkillControlState + ); +} + bool UHyperTwistContractLibrary::DeserializeTrainingTimerExportPacketFromJson( const FString& Json, FHyperTwistTrainingTimerExportPacket& OutTimerExportPacket diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSkills/HyperTwistSkillCoreLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSkills/HyperTwistSkillCoreLibrary.cpp index 9a6103e..d7d5f5d 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSkills/HyperTwistSkillCoreLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistSkills/HyperTwistSkillCoreLibrary.cpp @@ -120,6 +120,197 @@ namespace HyperTwistSkillCoreLibraryInternal FamilyCount.Count = Count; return FamilyCount; } + + FString MakeSkillSettingsSlug(const FString& SkillId) + { + FString Slug = SkillId; + Slug.ReplaceInline(TEXT("/"), TEXT(".")); + Slug.ReplaceInline(TEXT("-"), TEXT(".")); + return Slug; + } + + FString MakeEnableSettingsKey(const FString& SkillId) + { + return TEXT("skills.enabled.") + MakeSkillSettingsSlug(SkillId); + } + + FString MakeVisibilitySettingsKey(const FString& SkillId) + { + return TEXT("skills.visible.") + MakeSkillSettingsSlug(SkillId); + } + + FString MakeVisibilityGroupId(const EHyperTwistSkillFamily Family) + { + switch (Family) + { + case EHyperTwistSkillFamily::SubstrateGovernance: + return TEXT("skill-group/substrate-governance"); + case EHyperTwistSkillFamily::AnalysisReview: + return TEXT("skill-group/analysis-review"); + case EHyperTwistSkillFamily::MemoryContinuity: + return TEXT("skill-group/memory-continuity"); + case EHyperTwistSkillFamily::ProviderOperations: + return TEXT("skill-group/provider-operations"); + case EHyperTwistSkillFamily::TrainingCoaching: + return TEXT("skill-group/training-coaching"); + case EHyperTwistSkillFamily::DomainCreative: + return TEXT("skill-group/domain-creative"); + default: + return FString(); + } + } + + FString MakeVisibilityGroupLabel(const EHyperTwistSkillFamily Family) + { + switch (Family) + { + case EHyperTwistSkillFamily::SubstrateGovernance: + return TEXT("Substrate Governance"); + case EHyperTwistSkillFamily::AnalysisReview: + return TEXT("Analysis And Review"); + case EHyperTwistSkillFamily::MemoryContinuity: + return TEXT("Memory And Continuity"); + case EHyperTwistSkillFamily::ProviderOperations: + return TEXT("Provider And Operations"); + case EHyperTwistSkillFamily::TrainingCoaching: + return TEXT("Training And Coaching"); + case EHyperTwistSkillFamily::DomainCreative: + return TEXT("Domain And Creative"); + default: + return FString(); + } + } + + FString MakeVisibilityGroupSettingsKey(const EHyperTwistSkillFamily Family) + { + return TEXT("skills.group.visible.") + + MakeSkillSettingsSlug(MakeVisibilityGroupId(Family)); + } + + const FHyperTwistSkillControlOverride* FindControlOverride( + const FHyperTwistSkillControlProfile& ControlProfile, + const FString& SkillId + ) + { + for (const FHyperTwistSkillControlOverride& Override : ControlProfile.Overrides) + { + if (Override.SkillId == SkillId) + { + return &Override; + } + } + + return nullptr; + } + + FHyperTwistSkillMasterSwitchState MakeMasterSwitchState( + const FHyperTwistSkillControlProfile& ControlProfile + ) + { + FHyperTwistSkillMasterSwitchState MasterSwitch; + MasterSwitch.SettingsKey = TEXT("skills.master.enabled"); + MasterSwitch.DisplayLabel = TEXT("Enable Skills"); + MasterSwitch.bEnabled = ControlProfile.bMasterEnabled; + MasterSwitch.bDurableSettingExposed = ControlProfile.bDurableSettingsExposed; + MasterSwitch.bImmediateMenuControlExposed = ControlProfile.bImmediateMenuControlExposed; + MasterSwitch.bAllSkillsOffSafe = true; + MasterSwitch.Summary = + TEXT("Global master gate for optional assistive skills."); + return MasterSwitch; + } + + FHyperTwistSkillControlStateEntry MakeControlStateEntry( + const FHyperTwistSkillManifestEntry& Entry, + const FHyperTwistSkillControlProfile& ControlProfile + ) + { + const FHyperTwistSkillControlOverride* Override = + FindControlOverride(ControlProfile, Entry.SkillId); + const bool bRequestedEnabled = + (Override != nullptr && Override->bHasEnabledOverride) + ? Override->bEnabled + : Entry.bEnabledByDefault; + const bool bRequestedVisible = + (Override != nullptr && Override->bHasVisibilityOverride) + ? Override->bVisible + : Entry.bVisibleByDefault; + + FHyperTwistSkillControlStateEntry SkillState; + SkillState.SkillId = Entry.SkillId; + SkillState.DisplayLabel = Entry.DisplayLabel; + SkillState.EnableSettingsKey = MakeEnableSettingsKey(Entry.SkillId); + SkillState.VisibilitySettingsKey = MakeVisibilitySettingsKey(Entry.SkillId); + SkillState.VisibilityGroupId = MakeVisibilityGroupId(Entry.Family); + SkillState.Family = Entry.Family; + SkillState.Status = Entry.Status; + SkillState.bInstalled = Entry.bInstalledWhenDisabled; + SkillState.bOptionalAssistive = Entry.bOptionalAssistive; + SkillState.bRequestedEnabled = bRequestedEnabled; + SkillState.bEffectiveEnabled = ControlProfile.bMasterEnabled && bRequestedEnabled; + SkillState.bRequestedVisible = bRequestedVisible; + SkillState.bEffectiveVisible = bRequestedVisible; + SkillState.bInertWhenDisabled = Entry.bInertWhenDisabled; + SkillState.bDurableSettingExposed = ControlProfile.bDurableSettingsExposed; + SkillState.bImmediateMenuControlExposed = ControlProfile.bImmediateMenuControlExposed; + SkillState.Summary = Entry.Summary; + return SkillState; + } + + void AddOrUpdateVisibilityGroup( + FHyperTwistSkillControlState& ControlState, + const FHyperTwistSkillControlStateEntry& SkillState + ) + { + FHyperTwistSkillVisibilityGroupState* Group = ControlState.VisibilityGroups.FindByPredicate( + [&SkillState](const FHyperTwistSkillVisibilityGroupState& ExistingGroup) + { + return ExistingGroup.GroupId == SkillState.VisibilityGroupId; + } + ); + + if (Group == nullptr) + { + FHyperTwistSkillVisibilityGroupState NewGroup; + NewGroup.GroupId = SkillState.VisibilityGroupId; + NewGroup.DisplayLabel = MakeVisibilityGroupLabel(SkillState.Family); + NewGroup.VisibilitySettingsKey = MakeVisibilityGroupSettingsKey(SkillState.Family); + NewGroup.Family = SkillState.Family; + NewGroup.bGroupVisibleByDefault = SkillState.bRequestedVisible; + NewGroup.bDurableVisibilityControlExposed = SkillState.bDurableSettingExposed; + NewGroup.Summary = TEXT("Family-based visibility grouping for optional skills."); + ControlState.VisibilityGroups.Add(NewGroup); + Group = &ControlState.VisibilityGroups.Last(); + } + + Group->SkillIds.Add(SkillState.SkillId); + Group->VisibleSkillCount += SkillState.bEffectiveVisible ? 1 : 0; + Group->HiddenSkillCount += SkillState.bEffectiveVisible ? 0 : 1; + Group->bGroupVisibleByDefault |= SkillState.bRequestedVisible; + } + + FHyperTwistSkillControlProfile MakeDefaultControlProfile() + { + FHyperTwistSkillControlProfile ControlProfile; + ControlProfile.ProfileId = TEXT("skill-controls/default"); + ControlProfile.DisplayLabel = TEXT("Default Skill Controls"); + ControlProfile.bMasterEnabled = true; + ControlProfile.bDurableSettingsExposed = true; + ControlProfile.bImmediateMenuControlExposed = true; + ControlProfile.Summary = + TEXT("Default first-party skill control profile."); + return ControlProfile; + } + + FHyperTwistSkillControlProfile MakeAllSkillsOffControlProfile() + { + FHyperTwistSkillControlProfile ControlProfile = MakeDefaultControlProfile(); + ControlProfile.ProfileId = TEXT("skill-controls/all-skills-off"); + ControlProfile.DisplayLabel = TEXT("All Skills Off"); + ControlProfile.bMasterEnabled = false; + ControlProfile.Summary = + TEXT("Control profile proving the core product remains valid with all skills off."); + return ControlProfile; + } } FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistryState() @@ -143,7 +334,7 @@ FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistrySt EHyperTwistSkillFamily::SubstrateGovernance, EHyperTwistSkillStatus::ImplementedNow, true, - false, + true, { MakeCommandBinding( TEXT("command/skills/inspect-registry"), @@ -184,7 +375,7 @@ FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistrySt EHyperTwistSkillFamily::AnalysisReview, EHyperTwistSkillStatus::CommandContractPending, false, - false, + true, { MakeCommandBinding( TEXT("command/skills/review-architecture"), @@ -225,7 +416,7 @@ FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistrySt EHyperTwistSkillFamily::MemoryContinuity, EHyperTwistSkillStatus::CommandContractPending, false, - false, + true, { MakeCommandBinding( TEXT("command/skills/memory-resume-briefing"), @@ -266,7 +457,7 @@ FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistrySt EHyperTwistSkillFamily::ProviderOperations, EHyperTwistSkillStatus::CommandContractPending, false, - false, + true, { MakeCommandBinding( TEXT("command/skills/provider-routing-inspector"), @@ -413,3 +604,52 @@ FHyperTwistSkillRegistryState UHyperTwistSkillCoreLibrary::DeriveSkillRegistrySt return RegistryState; } + +FHyperTwistSkillControlState UHyperTwistSkillCoreLibrary::DeriveSkillControlState( + const FHyperTwistSkillRegistryState& RegistryState, + const FHyperTwistSkillControlProfile& ControlProfile +) +{ + using namespace HyperTwistSkillCoreLibraryInternal; + + if (!RegistryState.IsStructurallyValid() || !ControlProfile.IsStructurallyValid()) + { + return FHyperTwistSkillControlState(); + } + + FHyperTwistSkillControlState ControlState; + ControlState.RegistryId = RegistryState.RegistryId; + ControlState.ManifestVersion = TEXT("s1b-v1"); + ControlState.ReferenceUtc = TEXT("2026-05-28T21:15:00Z"); + ControlState.CommandSurfaceRootId = RegistryState.CommandSurfaceRootId; + ControlState.ControlProfileId = ControlProfile.ProfileId; + ControlState.MasterSwitch = MakeMasterSwitchState(ControlProfile); + ControlState.Summary = + TEXT("First-party skill settings, menu, and off-state control contract."); + + for (const FHyperTwistSkillManifestEntry& Entry : RegistryState.Entries) + { + const FHyperTwistSkillControlStateEntry SkillState = + MakeControlStateEntry(Entry, ControlProfile); + if (!SkillState.IsStructurallyValid()) + { + return FHyperTwistSkillControlState(); + } + + ControlState.SkillStates.Add(SkillState); + ControlState.EffectiveEnabledSkillCount += SkillState.bEffectiveEnabled ? 1 : 0; + ControlState.VisibleSkillCount += SkillState.bEffectiveVisible ? 1 : 0; + AddOrUpdateVisibilityGroup(ControlState, SkillState); + } + + ControlState.SkillCount = ControlState.SkillStates.Num(); + ControlState.EffectiveDisabledSkillCount = + ControlState.SkillCount - ControlState.EffectiveEnabledSkillCount; + ControlState.HiddenSkillCount = + ControlState.SkillCount - ControlState.VisibleSkillCount; + ControlState.bCoreProductWorksWithAllSkillsOff = true; + ControlState.bNoPromptBabysittingToDisable = true; + ControlState.bAllInstalledSkillsRemainReenableable = true; + + return ControlState; +} diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistBootstrap/HyperTwistContractLibrary.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistBootstrap/HyperTwistContractLibrary.h index b3381af..426d993 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistBootstrap/HyperTwistContractLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistBootstrap/HyperTwistContractLibrary.h @@ -167,6 +167,12 @@ public: UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills") static FHyperTwistSkillRegistryState MakeSampleSkillRegistryState(); + UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills") + static FHyperTwistSkillControlState MakeSampleSkillControlState(); + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills") + static FHyperTwistSkillControlState MakeAllSkillsOffSkillControlState(); + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training") static FHyperTwistTrainingRepositoryIntegrityReport MakeSampleTrainingRepositoryIntegrityReport(); @@ -361,6 +367,11 @@ public: const FHyperTwistSkillRegistryState& SkillRegistryState ); + UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization") + static FString SerializeSkillControlStateToJson( + const FHyperTwistSkillControlState& SkillControlState + ); + UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization") static FString SerializeTrainingTimerExportPacketToJson(const FHyperTwistTrainingTimerExportPacket& TimerExportPacket); @@ -439,6 +450,12 @@ public: FHyperTwistSkillRegistryState& OutSkillRegistryState ); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization") + static bool DeserializeSkillControlStateFromJson( + const FString& Json, + FHyperTwistSkillControlState& OutSkillControlState + ); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization") static bool DeserializeTrainingTimerExportPacketFromJson(const FString& Json, FHyperTwistTrainingTimerExportPacket& OutTimerExportPacket); }; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillCoreLibrary.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillCoreLibrary.h index 6d64ba1..60597dd 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillCoreLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillCoreLibrary.h @@ -13,4 +13,10 @@ class UNREALHYPERTWIST_API UHyperTwistSkillCoreLibrary : public UBlueprintFuncti public: UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills") static FHyperTwistSkillRegistryState DeriveSkillRegistryState(); + + UFUNCTION(BlueprintPure, Category = "HyperTwist|Skills") + static FHyperTwistSkillControlState DeriveSkillControlState( + const FHyperTwistSkillRegistryState& RegistryState, + const FHyperTwistSkillControlProfile& ControlProfile + ); }; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillTypes.h index f46c626..c9d7d9c 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillTypes.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistSkills/HyperTwistSkillTypes.h @@ -423,3 +423,381 @@ struct FHyperTwistSkillRegistryState return true; } }; + +USTRUCT(BlueprintType) +struct FHyperTwistSkillControlOverride +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SkillId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasEnabledOverride = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bEnabled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bHasVisibilityOverride = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bVisible = false; + + bool IsStructurallyValid() const + { + return !SkillId.IsEmpty() + && (bHasEnabledOverride || bHasVisibilityOverride); + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistSkillControlProfile +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ProfileId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DisplayLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bMasterEnabled = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bDurableSettingsExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bImmediateMenuControlExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray Overrides; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Summary; + + bool IsStructurallyValid() const + { + if (ProfileId.IsEmpty() + || DisplayLabel.IsEmpty() + || !bDurableSettingsExposed) + { + return false; + } + + TArray SeenSkillIds; + for (const FHyperTwistSkillControlOverride& Override : Overrides) + { + if (!Override.IsStructurallyValid() || SeenSkillIds.Contains(Override.SkillId)) + { + return false; + } + + SeenSkillIds.Add(Override.SkillId); + } + + return true; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistSkillMasterSwitchState +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SettingsKey; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DisplayLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bEnabled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bDurableSettingExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bImmediateMenuControlExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bAllSkillsOffSafe = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Summary; + + bool IsStructurallyValid() const + { + return !SettingsKey.IsEmpty() + && !DisplayLabel.IsEmpty() + && bDurableSettingExposed + && bAllSkillsOffSafe; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistSkillControlStateEntry +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString SkillId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DisplayLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString EnableSettingsKey; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString VisibilitySettingsKey; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString VisibilityGroupId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + EHyperTwistSkillFamily Family = EHyperTwistSkillFamily::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + EHyperTwistSkillStatus Status = EHyperTwistSkillStatus::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bInstalled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bOptionalAssistive = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bRequestedEnabled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bEffectiveEnabled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bRequestedVisible = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bEffectiveVisible = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bInertWhenDisabled = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bDurableSettingExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bImmediateMenuControlExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Summary; + + bool IsStructurallyValid() const + { + return !SkillId.IsEmpty() + && !DisplayLabel.IsEmpty() + && !EnableSettingsKey.IsEmpty() + && !VisibilitySettingsKey.IsEmpty() + && !VisibilityGroupId.IsEmpty() + && Family != EHyperTwistSkillFamily::None + && Status != EHyperTwistSkillStatus::None + && bInstalled + && bOptionalAssistive + && bInertWhenDisabled + && bDurableSettingExposed + && (!bEffectiveEnabled || bRequestedEnabled); + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistSkillVisibilityGroupState +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString GroupId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString DisplayLabel; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString VisibilitySettingsKey; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + EHyperTwistSkillFamily Family = EHyperTwistSkillFamily::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray SkillIds; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 VisibleSkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 HiddenSkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bGroupVisibleByDefault = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bDurableVisibilityControlExposed = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Summary; + + bool IsStructurallyValid() const + { + return !GroupId.IsEmpty() + && !DisplayLabel.IsEmpty() + && !VisibilitySettingsKey.IsEmpty() + && Family != EHyperTwistSkillFamily::None + && SkillIds.Num() > 0 + && VisibleSkillCount >= 0 + && HiddenSkillCount >= 0 + && (VisibleSkillCount + HiddenSkillCount) == SkillIds.Num() + && bDurableVisibilityControlExposed; + } +}; + +USTRUCT(BlueprintType) +struct FHyperTwistSkillControlState +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString RegistryId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ManifestVersion; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ReferenceUtc; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString CommandSurfaceRootId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString ControlProfileId; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FHyperTwistSkillMasterSwitchState MasterSwitch; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray SkillStates; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + TArray VisibilityGroups; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 SkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 EffectiveEnabledSkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 EffectiveDisabledSkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 VisibleSkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + int32 HiddenSkillCount = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bCoreProductWorksWithAllSkillsOff = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bNoPromptBabysittingToDisable = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + bool bAllInstalledSkillsRemainReenableable = false; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist") + FString Summary; + + bool IsStructurallyValid() const + { + if (RegistryId.IsEmpty() + || ManifestVersion.IsEmpty() + || ReferenceUtc.IsEmpty() + || CommandSurfaceRootId.IsEmpty() + || ControlProfileId.IsEmpty() + || !MasterSwitch.IsStructurallyValid() + || SkillStates.Num() == 0 + || SkillCount != SkillStates.Num() + || EffectiveDisabledSkillCount != (SkillCount - EffectiveEnabledSkillCount) + || HiddenSkillCount != (SkillCount - VisibleSkillCount) + || !bCoreProductWorksWithAllSkillsOff + || !bNoPromptBabysittingToDisable + || !bAllInstalledSkillsRemainReenableable) + { + return false; + } + + TArray SeenSkillIds; + int32 ComputedEnabledCount = 0; + int32 ComputedVisibleCount = 0; + bool bComputedNoBabysitting = true; + bool bComputedReenableable = true; + for (const FHyperTwistSkillControlStateEntry& SkillState : SkillStates) + { + if (!SkillState.IsStructurallyValid() || SeenSkillIds.Contains(SkillState.SkillId)) + { + return false; + } + + SeenSkillIds.Add(SkillState.SkillId); + ComputedEnabledCount += SkillState.bEffectiveEnabled ? 1 : 0; + ComputedVisibleCount += SkillState.bEffectiveVisible ? 1 : 0; + bComputedNoBabysitting &= SkillState.bDurableSettingExposed; + bComputedReenableable &= SkillState.bInstalled && SkillState.bInertWhenDisabled; + } + + if (ComputedEnabledCount != EffectiveEnabledSkillCount + || ComputedVisibleCount != VisibleSkillCount + || bComputedNoBabysitting != bNoPromptBabysittingToDisable + || bComputedReenableable != bAllInstalledSkillsRemainReenableable) + { + return false; + } + + TArray SeenGroupIds; + for (const FHyperTwistSkillVisibilityGroupState& Group : VisibilityGroups) + { + if (!Group.IsStructurallyValid() || SeenGroupIds.Contains(Group.GroupId)) + { + return false; + } + + int32 ComputedGroupVisibleCount = 0; + int32 ComputedGroupHiddenCount = 0; + for (const FString& SkillId : Group.SkillIds) + { + const FHyperTwistSkillControlStateEntry* SkillState = SkillStates.FindByPredicate( + [&SkillId](const FHyperTwistSkillControlStateEntry& Entry) + { + return Entry.SkillId == SkillId; + } + ); + if (SkillState == nullptr + || SkillState->Family != Group.Family + || SkillState->VisibilityGroupId != Group.GroupId) + { + return false; + } + + ComputedGroupVisibleCount += SkillState->bEffectiveVisible ? 1 : 0; + ComputedGroupHiddenCount += SkillState->bEffectiveVisible ? 0 : 1; + } + + if (ComputedGroupVisibleCount != Group.VisibleSkillCount + || ComputedGroupHiddenCount != Group.HiddenSkillCount) + { + return false; + } + + SeenGroupIds.Add(Group.GroupId); + } + + return true; + } +}; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistSkillPhaseS1BSettingsVisibilityContractTest.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistSkillPhaseS1BSettingsVisibilityContractTest.cpp new file mode 100644 index 0000000..b02afb3 --- /dev/null +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistSkillPhaseS1BSettingsVisibilityContractTest.cpp @@ -0,0 +1,276 @@ +// Copyright HyperTwist, Inc. All Rights Reserved. + +#include "Misc/AutomationTest.h" + +#include "HyperTwistBootstrap/HyperTwistContractLibrary.h" + +#if WITH_AUTOMATION_TESTS + +namespace HyperTwistSkillPhaseS1BTestInternal +{ + const FHyperTwistSkillControlStateEntry* FindSkillStateById( + const FHyperTwistSkillControlState& ControlState, + const FString& SkillId + ) + { + for (const FHyperTwistSkillControlStateEntry& SkillState : ControlState.SkillStates) + { + if (SkillState.SkillId == SkillId) + { + return &SkillState; + } + } + + return nullptr; + } + + const FHyperTwistSkillVisibilityGroupState* FindVisibilityGroupById( + const FHyperTwistSkillControlState& ControlState, + const FString& GroupId + ) + { + for (const FHyperTwistSkillVisibilityGroupState& Group : ControlState.VisibilityGroups) + { + if (Group.GroupId == GroupId) + { + return &Group; + } + } + + return nullptr; + } +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistSkillPhaseS1BSettingsVisibilityTest, + "HyperTwist.FirstParty.Skill.PhaseS1B.SettingsVisibility", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistSkillPhaseS1BSettingsVisibilityTest::RunTest( + const FString& Parameters +) +{ + const FHyperTwistSkillControlState ControlState = + UHyperTwistContractLibrary::MakeSampleSkillControlState(); + + TestTrue( + TEXT("The Phase S1-B skill-control state must be structurally valid."), + ControlState.IsStructurallyValid() + ); + TestTrue( + TEXT("The master switch must be enabled in the default control profile."), + ControlState.MasterSwitch.bEnabled + ); + TestTrue( + TEXT("The S1-B control state must expose durable settings."), + ControlState.MasterSwitch.bDurableSettingExposed + ); + TestTrue( + TEXT("The S1-B control state must expose immediate menu control."), + ControlState.MasterSwitch.bImmediateMenuControlExposed + ); + TestEqual( + TEXT("The sample S1-B control state must preserve all six installed skills."), + ControlState.SkillCount, + 6 + ); + TestEqual( + TEXT("The default S1-B control state must keep one effective enabled skill."), + ControlState.EffectiveEnabledSkillCount, + 1 + ); + TestTrue( + TEXT("The S1-B control state must keep visible family groupings."), + ControlState.VisibilityGroups.Num() > 0 + ); + + const FHyperTwistSkillControlStateEntry* GovernanceState = + HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById( + ControlState, + TEXT("skill/skillization-governance") + ); + TestNotNull( + TEXT("The governance skill state must exist."), + GovernanceState + ); + if (GovernanceState != nullptr) + { + TestTrue( + TEXT("The governance skill must remain effectively enabled by default."), + GovernanceState->bEffectiveEnabled + ); + TestTrue( + TEXT("The governance skill must remain visible by default."), + GovernanceState->bEffectiveVisible + ); + TestEqual( + TEXT("The governance skill must use the substrate visibility group."), + GovernanceState->VisibilityGroupId, + TEXT("skill-group/substrate-governance") + ); + } + + const FHyperTwistSkillVisibilityGroupState* GovernanceGroup = + HyperTwistSkillPhaseS1BTestInternal::FindVisibilityGroupById( + ControlState, + TEXT("skill-group/substrate-governance") + ); + TestNotNull( + TEXT("The substrate-governance visibility group must exist."), + GovernanceGroup + ); + if (GovernanceGroup != nullptr) + { + TestEqual( + TEXT("The governance visibility group must contain one skill."), + GovernanceGroup->SkillIds.Num(), + 1 + ); + TestEqual( + TEXT("The governance visibility group must expose one visible skill."), + GovernanceGroup->VisibleSkillCount, + 1 + ); + } + + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistSkillPhaseS1BAllSkillsOffCorrectnessTest, + "HyperTwist.FirstParty.Skill.PhaseS1B.AllSkillsOffCorrectness", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistSkillPhaseS1BAllSkillsOffCorrectnessTest::RunTest( + const FString& Parameters +) +{ + const FHyperTwistSkillControlState ControlState = + UHyperTwistContractLibrary::MakeAllSkillsOffSkillControlState(); + + TestTrue( + TEXT("The all-skills-off S1-B control state must remain structurally valid."), + ControlState.IsStructurallyValid() + ); + TestFalse( + TEXT("The master switch must be disabled in the all-skills-off profile."), + ControlState.MasterSwitch.bEnabled + ); + TestTrue( + TEXT("The all-skills-off control state must confirm off-state safety."), + ControlState.MasterSwitch.bAllSkillsOffSafe + ); + TestEqual( + TEXT("The all-skills-off control state must expose zero effective enabled skills."), + ControlState.EffectiveEnabledSkillCount, + 0 + ); + TestEqual( + TEXT("The all-skills-off control state must preserve all installed skills as disabled."), + ControlState.EffectiveDisabledSkillCount, + ControlState.SkillCount + ); + TestTrue( + TEXT("The core product must still work with all skills off."), + ControlState.bCoreProductWorksWithAllSkillsOff + ); + TestTrue( + TEXT("Disabled skills must remain reenableable."), + ControlState.bAllInstalledSkillsRemainReenableable + ); + + const FHyperTwistSkillControlStateEntry* GovernanceState = + HyperTwistSkillPhaseS1BTestInternal::FindSkillStateById( + ControlState, + TEXT("skill/skillization-governance") + ); + TestNotNull( + TEXT("The governance skill state must still exist with all skills off."), + GovernanceState + ); + if (GovernanceState != nullptr) + { + TestTrue( + TEXT("The governance skill must stay requested-enabled by default."), + GovernanceState->bRequestedEnabled + ); + TestFalse( + TEXT("The governance skill must become effectively disabled when the master switch is off."), + GovernanceState->bEffectiveEnabled + ); + TestTrue( + TEXT("The governance skill must remain installed when disabled."), + GovernanceState->bInstalled + ); + TestTrue( + TEXT("The governance skill must remain inert when disabled."), + GovernanceState->bInertWhenDisabled + ); + } + + return true; +} + +IMPLEMENT_SIMPLE_AUTOMATION_TEST( + FHyperTwistSkillPhaseS1BSerializationRoundTripTest, + "HyperTwist.FirstParty.Skill.PhaseS1B.SerializationRoundTrip", + EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter +) + +bool FHyperTwistSkillPhaseS1BSerializationRoundTripTest::RunTest( + const FString& Parameters +) +{ + const FHyperTwistSkillControlState ControlState = + UHyperTwistContractLibrary::MakeSampleSkillControlState(); + TestTrue( + TEXT("The Phase S1-B skill-control state must be structurally valid before serialization."), + ControlState.IsStructurallyValid() + ); + + const FString Json = + UHyperTwistContractLibrary::SerializeSkillControlStateToJson(ControlState); + TestFalse(TEXT("The serialized S1-B JSON must not be empty."), Json.IsEmpty()); + TestTrue( + TEXT("The serialized S1-B JSON must expose the master-switch contract."), + Json.Contains(TEXT("MasterSwitch")) + ); + TestTrue( + TEXT("The serialized S1-B JSON must expose visibility groups."), + Json.Contains(TEXT("VisibilityGroups")) + ); + + FHyperTwistSkillControlState RoundTrippedState; + TestTrue( + TEXT("The S1-B JSON must deserialize cleanly."), + UHyperTwistContractLibrary::DeserializeSkillControlStateFromJson( + Json, + RoundTrippedState + ) + ); + TestTrue( + TEXT("The round-tripped S1-B control state must remain structurally valid."), + RoundTrippedState.IsStructurallyValid() + ); + TestEqual( + TEXT("The round-tripped S1-B control state must preserve skill counts."), + RoundTrippedState.SkillCount, + ControlState.SkillCount + ); + TestEqual( + TEXT("The round-tripped S1-B control state must preserve effective enabled counts."), + RoundTrippedState.EffectiveEnabledSkillCount, + ControlState.EffectiveEnabledSkillCount + ); + TestEqual( + TEXT("The round-tripped S1-B control state must preserve visibility-group counts."), + RoundTrippedState.VisibilityGroups.Num(), + ControlState.VisibilityGroups.Num() + ); + + return true; +} + +#endif diff --git a/docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_IMPLEMENTATION_PACKET_2026-05-28.md b/docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_IMPLEMENTATION_PACKET_2026-05-28.md new file mode 100644 index 0000000..7d20c5f --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_IMPLEMENTATION_PACKET_2026-05-28.md @@ -0,0 +1,109 @@ +# HyperTwist Phase S1-B first-party skill settings, menu, and off-state control implementation packet + +Created on `2026-05-28` + +## Status + +- first-party HyperTwist packet +- bounded `Phase S1-B` implementation slice + +## Purpose + +This packet lands the bounded first-party skill settings, menu, and off-state +control seam under the canonical `Skillization And Command Surface` doctrine. + +The landed slice is: + +- global skill enable/disable master switch +- per-skill enable/disable state +- visibility grouping + +It is not: + +- invocation/provenance audit ledger execution +- permissive analyzer wrappers +- restrictive clean-room command-contract specs +- wrapper execution or donor command promotion + +## Current authority basis + +This implementation packet stands on: + +- `docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md` +- `docs/ops/HYPERTWIST_OPTIONAL_ASSISTIVE_FEATURE_DEACTIVATION_AND_REMOVABILITY_DOCTRINE_2026-05-21.md` +- `docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md` +- `docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_PREPARATION_PACKET_2026-05-28.md` + +The preserved owners do not change: + +- first-party HyperTwist remains the owner of the product command surface +- the landed `Phase S1-A` registry remains the current authoritative substrate + beneath this packet +- optional assistive skills remain product-owned adjunct declarations rather + than donor command truth + +## Landed scope + +The current code now owns a bounded first-party skill-control seam through: + +- canonical skill control-profile, master-switch, per-skill control-state, + visibility-group, and aggregate control-state types in: + - `HyperTwistSkillTypes.h` +- first-party control-state derivation over the landed `S1-A` registry in: + - `UHyperTwistSkillCoreLibrary` +- current bounded control coverage for: + - durable global skill master-switch declaration + - per-skill durable enable/disable settings keys + - per-skill requested/effective enable state + - per-skill requested/effective visibility state + - family-based visibility groups + - immediate menu-control exposure declarations + - all-skills-off correctness +- sample contract helpers in: + - `UHyperTwistContractLibrary::MakeSampleSkillControlState()` + - `UHyperTwistContractLibrary::MakeAllSkillsOffSkillControlState()` + - `UHyperTwistContractLibrary::SerializeSkillControlStateToJson(...)` + - `UHyperTwistContractLibrary::DeserializeSkillControlStateFromJson(...)` +- focused automation coverage in: + - `HyperTwistSkillPhaseS1BSettingsVisibilityContractTest.cpp` + +## Why this is still intentionally bounded + +This packet lands control-state and visibility-group contracts only. + +Still deferred: + +- invocation/provenance audit ledger execution +- permissive analyzer wrappers +- restrictive clean-room command-contract specs + +## Validation + +Build validation: + +- `UnrealHyperTwistEditor Win64 Development` + +Focused automation validation: + +- `HyperTwist.FirstParty.Skill.PhaseS1B.SettingsVisibility` +- `HyperTwist.FirstParty.Skill.PhaseS1B.AllSkillsOffCorrectness` +- `HyperTwist.FirstParty.Skill.PhaseS1B.SerializationRoundTrip` + +Observed: + +- `3` focused `Phase S1-B` automation tests succeeded + +## Queue effect + +This packet consumes the current `Phase S1-B` implementation slice. + +After this landing: + +- `S1-B` is landed in current code +- `S1-C` is the next clean skillization move +- do not jump straight from `S1-B` to analyzer wrappers or restrictive command + specs diff --git a/docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_PREPARATION_PACKET_2026-05-28.md b/docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_PREPARATION_PACKET_2026-05-28.md new file mode 100644 index 0000000..ed4d028 --- /dev/null +++ b/docs/arch/HYPERTWIST_PHASES1_B_FIRST_PARTY_SKILL_SETTINGS_MENU_AND_OFF_STATE_CONTROL_PREPARATION_PACKET_2026-05-28.md @@ -0,0 +1,101 @@ +# HyperTwist Phase S1-B first-party skill settings, menu, and off-state control preparation packet + +Created on `2026-05-28` + +## Status + +- first-party HyperTwist packet +- source-backed `Phase S1-B` preparation/control slice + +## Purpose + +This packet scopes the second bounded product implementation slice under the +canonical `Skillization And Command Surface` doctrine. + +The granted slice is: + +- global skill enable/disable master switch +- per-skill enable/disable state +- visibility grouping + +It is not: + +- invocation/provenance audit ledger execution +- permissive analyzer wrappers +- restrictive clean-room command-contract specs +- wrapper execution or donor command promotion + +## Current authority basis + +This control pass stands on: + +- `docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md` +- `docs/ops/HYPERTWIST_OPTIONAL_ASSISTIVE_FEATURE_DEACTIVATION_AND_REMOVABILITY_DOCTRINE_2026-05-21.md` +- `docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md` +- `docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md` +- `docs/arch/HYPERTWIST_PHASES1_A_FIRST_PARTY_SKILL_REGISTRY_AND_MANIFEST_CONTRACT_IMPLEMENTATION_PACKET_2026-05-28.md` + +The preserved owners do not change here: + +- first-party HyperTwist remains the owner of the product command surface +- the landed `Phase S1-A` registry remains the authoritative substrate + beneath this packet +- optional assistive skills remain product-owned adjuncts rather than donor + command truth + +## Granted family + +The bounded `Phase S1-B` slice may land: + +1. first-party skill control profile and master-switch state +2. first-party per-skill requested/effective enable state +3. first-party per-skill requested/effective visibility state +4. family-based visibility grouping +5. explicit all-skills-off correctness +6. sample control-state and JSON round-trip coverage + +The packet must stay out of: + +- invocation record storage +- service/wrapper execution +- restrictive clean-room command specs + +## Proposed implementation shape + +Land the narrower first-party boundary through: + +- new skill types for: + - control profile + - master switch + - per-skill control-state entries + - visibility groups + - bounded control-state aggregate +- a first-party skill-core derivation function over the landed `S1-A` registry +- sample-contract helpers for: + - default control-state derivation + - all-skills-off derivation + - JSON serialization + - JSON deserialization +- focused automation in: + - `HyperTwistSkillPhaseS1BSettingsVisibilityContractTest.cpp` + +## Validation target + +Validate with: + +- Unreal build for `UnrealHyperTwistEditor Win64 Development` +- focused automation: + - `HyperTwist.FirstParty.Skill.PhaseS1B.SettingsVisibility` + - `HyperTwist.FirstParty.Skill.PhaseS1B.AllSkillsOffCorrectness` + - `HyperTwist.FirstParty.Skill.PhaseS1B.SerializationRoundTrip` + +## Queue effect + +If this packet lands cleanly: + +- `S1-B` is consumed +- `S1-C` becomes the next clean move +- do not jump straight from `S1-B` to analyzer wrappers or restrictive specs diff --git a/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md b/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md index 18a6af3..1fe9a07 100644 --- a/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md +++ b/docs/ops/HYPERTWIST_IMPLEMENTATION_PHASE_1_KICKOFF.md @@ -273,6 +273,9 @@ Specifically: - the bounded first-party `Phase S1-A` skill registry and manifest contract packet is now landed in current code -- `S1-B` settings/menu/off-state control is the next clean move -- `S2-A` permissive analyzer wrappers stay deferred until `S1-B` lands +- the bounded first-party `Phase S1-B` settings/menu/off-state control packet + is now landed in current code +- `S1-C` invocation/provenance/audit ledger is the next clean move +- `S1-D` authoring/examples/validation-harness expansion stays after `S1-C` +- `S2-A` permissive analyzer wrappers stay deferred until `S1-D` lands - `S2-B` clean-room command-contract specs stay deferred until `S2-A` diff --git a/docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md b/docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md index b659459..d5d3913 100644 --- a/docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md +++ b/docs/ops/HYPERTWIST_SKILLIZATION_AND_COMMAND_SURFACE_DOCTRINE_2026-05-21.md @@ -220,6 +220,13 @@ Acceptance gates: - core product still works with all skills off - no skill requires prompt babysitting to disable +Current state: + +- the bounded first-party `Phase S1-B` settings/menu/off-state control packet + is now landed in current code +- invocation/provenance audit ledger execution remains deferred to `S1-C` +- analyzer wrappers remain deferred to `S2-A` + #### `S1-C` invocation, provenance, and audit ledger Outputs: @@ -457,9 +464,10 @@ These are target-shape command families, not claims of implemented reality. The next correct sequence is: -1. `S1-B` per-skill settings/menu exposure and off-state behavior -2. `S2-A` permissive analyzer wrappers -3. `S2-B` clean-room command-contract specs for restrictive lanes +1. `S1-C` invocation, provenance, and audit ledger +2. `S1-D` authoring, examples, and validation harness +3. `S2-A` permissive analyzer wrappers +4. `S2-B` clean-room command-contract specs for restrictive lanes Broader memory, browser, workflow, provider, and domain skill widening should wait until that base exists. diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md b/docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md index 8782457..4af86e6 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md @@ -237,4 +237,6 @@ Future skill growth must follow: - the bounded first-party `Phase S1-A` registry/manifest seam is now the live product base for skill status, command binding, permission, and provenance declarations -- `S1-B` remains the next clean move before any wrapper widening +- the bounded first-party `Phase S1-B` control seam is now the live product + base for durable off-state behavior and family visibility grouping +- `S1-C` remains the next clean move before any wrapper widening 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 229e0b9..2d2ae36 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md @@ -304,7 +304,7 @@ repo. | Feature | Status | Primary authority | Notes | |---|---|---|---| -| First-party skill registry and enable/disable governance | Implemented now | landed first-party `Phase S1-A` packet | Current bounded first-party skill status/family contracts, command/service binding declarations, permission/scope declarations, provenance/log declarations, manifest entries, registry counts, and disabled-but-installed inert-off-state truth are live. Settings/menu controls and invocation ledger execution remain deferred to later bounded skillization stages. | +| First-party skill registry and enable/disable governance | Implemented now | landed first-party `Phase S1-A` and `Phase S1-B` packets | Current bounded first-party skill status/family contracts, command/service binding declarations, permission/scope declarations, provenance/log declarations, manifest entries, registry counts, durable master-switch/per-skill control-state, family visibility groups, and disabled-but-installed inert-off-state truth are live. Invocation ledger execution remains deferred to later bounded skillization stages. | | Review/analyzer skill family | Deep-source grounded retained | skillization doctrine | Planned after substrate and off-state controls. | | Memory/continuity skill family | Deep-source grounded retained | skillization + memory doctrine | Retained, not implemented. | | Provider/ops skill family | Deep-source grounded retained | skillization + provider doctrine | Retained, not implemented. | diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md b/docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md index b5eef93..534a56c 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/PROVENANCE_AND_TRUST_MODEL.md @@ -101,6 +101,8 @@ The landed bounded first-party `Phase S1-A` packet keeps: - command/service bindings declared rather than inferred ad hoc - permission/scope declarations explicit - provenance/log expectations declared before later invocation-ledger storage +- the landed bounded first-party `Phase S1-B` packet keeps durable master and + per-skill off-state control first-party rather than hidden prompt babysitting ## Memory-specific consequence diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md index 2e99842..359a8f7 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md @@ -161,7 +161,11 @@ Canonical discovery surfaces for roadmap interpretation: control pass is now consumed - the bounded first-party `Phase S1-A` skill registry and manifest contract packet is now landed in current code -- `S1-B` settings/menu/off-state control is now the next clean skillization +- the generic first-party `Phase S1-B` skill settings/menu/off-state control + pass is now consumed +- the bounded first-party `Phase S1-B` skill settings/menu/off-state control + packet is now landed in current code +- `S1-C` invocation/provenance/audit ledger is now the next clean skillization move - the generic source-backed `Phase 6R-R` shared classic-cube recognition multi-face correction/explanation control pass is now consumed diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md b/docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md index 9882e2d..0bfa1f2 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/SKILLS.md @@ -54,13 +54,15 @@ Includes: - landed now: - skill registry/manifest contract + - enable/disable controls + - visibility grouping - command/service binding declarations - permission/scope declarations - provenance/log declarations - validation harness - still deferred: - - enable/disable controls - provenance/invocation ledger execution + - authoring template expansion ### Analyzer and review skills @@ -126,9 +128,10 @@ A coding model working on HyperTwist should still be able to: The next correct skillization sequence is: -1. settings/menu/off-state controls -2. permissive analyzer wrappers -3. clean-room command-contract specs for restrictive lanes +1. invocation/provenance/audit ledger +2. authoring/examples/validation harness expansion +3. permissive analyzer wrappers +4. clean-room command-contract specs for restrictive lanes Broader memory, provider, and domain skill widening should wait until that base exists.