feat: harden browser surfaces and settings ownership

This commit is contained in:
axiomlogicnexus 2026-06-28 05:58:48 +00:00
parent 42fcd54ecc
commit e2d3438741
17 changed files with 890 additions and 20 deletions

View file

@ -1330,6 +1330,38 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
Magic120CellViewContextSurface.PrimaryViewProfileContractId,
Magic120CellViewProfileContract
) && Magic120CellViewProfileContract.IsStructurallyValid();
Surface.Magic120CellProjectionSurfaceTagCount =
Magic120CellViewProfileContract.ProjectionSurfaceTags.Num();
Surface.Magic120CellSymmetryPresetTagCount =
Magic120CellViewProfileContract.SymmetryPresetTags.Num();
Surface.Magic120CellVisibilityPresetTagCount =
Magic120CellViewProfileContract.VisibilityPresetTags.Num();
Surface.Magic120CellFocusSurfaceTagCount =
Magic120CellViewProfileContract.FocusSurfaceTags.Num();
FHyperTwistTrainingHigherDimensionalRuntimeSessionSurface Magic120CellSessionSurface;
Surface.bMagic120CellPersistenceSettingsReady =
UHyperTwistTrainingRuntimeLibrary::TryGetBundledHigherDimensionalRuntimeSessionSurfaceByActivationProfileId(
TEXT("magic120cell-cleanroom-runtime-activation"),
Magic120CellSessionSurface
) && Magic120CellSessionSurface.IsStructurallyValid();
if (Surface.bMagic120CellPersistenceSettingsReady)
{
Surface.Magic120CellSessionSurfaceId = Magic120CellSessionSurface.SessionSurfaceId;
Surface.Magic120CellPersistenceBoundaryId =
Magic120CellSessionSurface.PrimaryPersistenceBoundaryId;
}
FHyperTwistTrainingHigherDimensionalInteractiveSceneSurface Magic120CellSceneSurface;
Surface.bMagic120CellPersistenceSettingsReady =
Surface.bMagic120CellPersistenceSettingsReady
&& UHyperTwistTrainingRuntimeLibrary::TryGetBundledHigherDimensionalInteractiveSceneSurfaceByActivationProfileId(
TEXT("magic120cell-cleanroom-runtime-activation"),
Magic120CellSceneSurface
) && Magic120CellSceneSurface.IsStructurallyValid();
if (Surface.bMagic120CellPersistenceSettingsReady)
{
Surface.Magic120CellSceneSurfaceId = Magic120CellSceneSurface.SceneSurfaceId;
Surface.Magic120CellStateSemanticsId = Magic120CellSceneSurface.StateSemanticsId;
}
FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface MagicCube5DViewContextSurface;
const bool bMagicCube5DViewContextReady =
@ -1347,16 +1379,64 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
MagicCube5DViewContextSurface.PrimaryViewProfileContractId,
MagicCube5DViewProfileContract
) && MagicCube5DViewProfileContract.IsStructurallyValid();
Surface.MagicCube5DProjectionSurfaceTagCount =
MagicCube5DViewProfileContract.ProjectionSurfaceTags.Num();
Surface.MagicCube5DStereoSurfaceTagCount =
MagicCube5DViewProfileContract.StereoSurfaceTags.Num();
Surface.MagicCube5DVisibilitySurfaceTagCount =
MagicCube5DViewProfileContract.VisibilitySurfaceTags.Num();
Surface.MagicCube5DFocusSurfaceTagCount =
MagicCube5DViewProfileContract.FocusSurfaceTags.Num();
FHyperTwistTrainingHigherDimensionalRuntimeSessionSurface MagicCube5DSessionSurface;
Surface.bMagicCube5DPersistenceSettingsReady =
UHyperTwistTrainingRuntimeLibrary::TryGetBundledHigherDimensionalRuntimeSessionSurfaceByActivationProfileId(
TEXT("magiccube5d-cleanroom-runtime-activation"),
MagicCube5DSessionSurface
) && MagicCube5DSessionSurface.IsStructurallyValid();
if (Surface.bMagicCube5DPersistenceSettingsReady)
{
Surface.MagicCube5DSessionSurfaceId = MagicCube5DSessionSurface.SessionSurfaceId;
Surface.MagicCube5DPersistenceBoundaryId =
MagicCube5DSessionSurface.PrimaryPersistenceBoundaryId;
}
FHyperTwistTrainingHigherDimensionalInteractiveSceneSurface MagicCube5DSceneSurface;
Surface.bMagicCube5DPersistenceSettingsReady =
Surface.bMagicCube5DPersistenceSettingsReady
&& UHyperTwistTrainingRuntimeLibrary::TryGetBundledHigherDimensionalInteractiveSceneSurfaceByActivationProfileId(
TEXT("magiccube5d-cleanroom-runtime-activation"),
MagicCube5DSceneSurface
) && MagicCube5DSceneSurface.IsStructurallyValid();
if (Surface.bMagicCube5DPersistenceSettingsReady)
{
Surface.MagicCube5DSceneSurfaceId = MagicCube5DSceneSurface.SceneSurfaceId;
Surface.MagicCube5DStateSemanticsId = MagicCube5DSceneSurface.StateSemanticsId;
}
const FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface ActiveViewContextSurface =
HasDisplayedHigherDimensionalRuntimeViewContextSurface()
? GetDisplayedHigherDimensionalRuntimeViewContextSurface()
: FHyperTwistTrainingHigherDimensionalRuntimeViewContextSurface();
const FHyperTwistTrainingHigherDimensionalRuntimeSessionSurface ActiveSessionSurface =
HasDisplayedHigherDimensionalRuntimeSessionSurface()
? GetDisplayedHigherDimensionalRuntimeSessionSurface()
: FHyperTwistTrainingHigherDimensionalRuntimeSessionSurface();
const FHyperTwistTrainingHigherDimensionalInteractiveSceneSurface ActiveSceneSurface =
HasDisplayedHigherDimensionalInteractiveSceneSurface()
? GetDisplayedHigherDimensionalInteractiveSceneSurface()
: FHyperTwistTrainingHigherDimensionalInteractiveSceneSurface();
Surface.bActiveHigherDimensionalSettingsVisible = ActiveViewContextSurface.IsStructurallyValid();
Surface.ActiveHigherDimensionalViewContextId =
Surface.bActiveHigherDimensionalSettingsVisible
? ActiveViewContextSurface.ViewContextSurfaceId
: TEXT("none");
Surface.ActiveHigherDimensionalSessionSurfaceId =
ActiveSessionSurface.IsStructurallyValid()
? ActiveSessionSurface.SessionSurfaceId
: TEXT("none");
Surface.ActiveHigherDimensionalInteractiveSceneSurfaceId =
ActiveSceneSurface.IsStructurallyValid()
? ActiveSceneSurface.SceneSurfaceId
: TEXT("none");
Surface.ActiveHigherDimensionalSelectorCount =
Surface.bActiveHigherDimensionalSettingsVisible
? ActiveViewContextSurface.Selectors.Num()
@ -1397,17 +1477,63 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
!Surface.ActiveHigherDimensionalViewContextId.IsEmpty()
? Surface.ActiveHigherDimensionalViewContextId
: TEXT("none");
const FString ActiveSessionSurfaceId =
!Surface.ActiveHigherDimensionalSessionSurfaceId.IsEmpty()
? Surface.ActiveHigherDimensionalSessionSurfaceId
: TEXT("none");
const FString ActiveSceneSurfaceId =
!Surface.ActiveHigherDimensionalInteractiveSceneSurfaceId.IsEmpty()
? Surface.ActiveHigherDimensionalInteractiveSceneSurfaceId
: TEXT("none");
const FString Magic120CellProfileId =
!Surface.Magic120CellViewProfileContractId.IsEmpty()
? Surface.Magic120CellViewProfileContractId
: TEXT("n/a");
const FString Magic120CellSessionSurfaceId =
!Surface.Magic120CellSessionSurfaceId.IsEmpty()
? Surface.Magic120CellSessionSurfaceId
: TEXT("n/a");
const FString Magic120CellSceneSurfaceId =
!Surface.Magic120CellSceneSurfaceId.IsEmpty()
? Surface.Magic120CellSceneSurfaceId
: TEXT("n/a");
const FString Magic120CellPersistenceBoundaryId =
!Surface.Magic120CellPersistenceBoundaryId.IsEmpty()
? Surface.Magic120CellPersistenceBoundaryId
: TEXT("n/a");
const FString Magic120CellStateSemanticsId =
!Surface.Magic120CellStateSemanticsId.IsEmpty()
? Surface.Magic120CellStateSemanticsId
: TEXT("n/a");
const FString MagicCube5DProfileId =
!Surface.MagicCube5DViewProfileContractId.IsEmpty()
? Surface.MagicCube5DViewProfileContractId
: TEXT("n/a");
const FString MagicCube5DSessionSurfaceId =
!Surface.MagicCube5DSessionSurfaceId.IsEmpty()
? Surface.MagicCube5DSessionSurfaceId
: TEXT("n/a");
const FString MagicCube5DSceneSurfaceId =
!Surface.MagicCube5DSceneSurfaceId.IsEmpty()
? Surface.MagicCube5DSceneSurfaceId
: TEXT("n/a");
const FString MagicCube5DPersistenceBoundaryId =
!Surface.MagicCube5DPersistenceBoundaryId.IsEmpty()
? Surface.MagicCube5DPersistenceBoundaryId
: TEXT("n/a");
const FString MagicCube5DStateSemanticsId =
!Surface.MagicCube5DStateSemanticsId.IsEmpty()
? Surface.MagicCube5DStateSemanticsId
: TEXT("n/a");
const bool bMagic120CellOwnedSettingsReady =
Surface.bMagic120CellViewSettingsReady
&& Surface.bMagic120CellPersistenceSettingsReady;
const bool bMagicCube5DOwnedSettingsReady =
Surface.bMagicCube5DViewSettingsReady
&& Surface.bMagicCube5DPersistenceSettingsReady;
Surface.SummaryLine =
TEXT("Camera, immersive, and dedicated-family view settings are already first-party owned, while XR/controller rebinding still remains unfinished.");
TEXT("Camera, immersive, and dedicated-family projection, selector, and persistence settings are already first-party owned, while XR/controller rebinding still remains unfinished.");
Surface.CameraSettingsLine = FString::Printf(
TEXT("Viewer camera settings: %s | tool %s | orbit/framing/export surface is owned."),
*HyperTwistTrainingPanelWidgetInternal::DescribeReadyState(
@ -1422,24 +1548,42 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
ImmersivePresenceContract.ReducedDistractionPresetIds.Num()
);
Surface.Magic120CellSettingsLine = FString::Printf(
TEXT("Magic120Cell view settings: %s | profile %s | selectors %d."),
TEXT("Magic120Cell owned settings: %s | profile %s | session %s | scene %s | persistence %s | semantics %s | selectors %d | projection tags %d | symmetry presets %d | visibility presets %d | focus surfaces %d."),
*HyperTwistTrainingPanelWidgetInternal::DescribeReadyState(
Surface.bMagic120CellViewSettingsReady),
bMagic120CellOwnedSettingsReady),
*Magic120CellProfileId,
Surface.Magic120CellSelectorCount
*Magic120CellSessionSurfaceId,
*Magic120CellSceneSurfaceId,
*Magic120CellPersistenceBoundaryId,
*Magic120CellStateSemanticsId,
Surface.Magic120CellSelectorCount,
Surface.Magic120CellProjectionSurfaceTagCount,
Surface.Magic120CellSymmetryPresetTagCount,
Surface.Magic120CellVisibilityPresetTagCount,
Surface.Magic120CellFocusSurfaceTagCount
);
Surface.MagicCube5DSettingsLine = FString::Printf(
TEXT("MagicCube5D view settings: %s | profile %s | selectors %d."),
TEXT("MagicCube5D owned settings: %s | profile %s | session %s | scene %s | persistence %s | semantics %s | selectors %d | projection tags %d | stereo tags %d | visibility tags %d | focus surfaces %d."),
*HyperTwistTrainingPanelWidgetInternal::DescribeReadyState(
Surface.bMagicCube5DViewSettingsReady),
bMagicCube5DOwnedSettingsReady),
*MagicCube5DProfileId,
Surface.MagicCube5DSelectorCount
*MagicCube5DSessionSurfaceId,
*MagicCube5DSceneSurfaceId,
*MagicCube5DPersistenceBoundaryId,
*MagicCube5DStateSemanticsId,
Surface.MagicCube5DSelectorCount,
Surface.MagicCube5DProjectionSurfaceTagCount,
Surface.MagicCube5DStereoSurfaceTagCount,
Surface.MagicCube5DVisibilitySurfaceTagCount,
Surface.MagicCube5DFocusSurfaceTagCount
);
Surface.SelectorSettingsLine = FString::Printf(
TEXT("Higher-dimensional selector ownership: %s | active context %s | active selectors %d."),
TEXT("Higher-dimensional selector ownership: %s | active context %s | active session %s | active scene %s | active selectors %d."),
*HyperTwistTrainingPanelWidgetInternal::DescribeReadyState(
Surface.bHigherDimensionalSelectorSettingsReady),
*ActiveViewContextId,
*ActiveSessionSurfaceId,
*ActiveSceneSurfaceId,
Surface.ActiveHigherDimensionalSelectorCount
);
Surface.SelectorRecallLine =
@ -1451,11 +1595,11 @@ UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurfa
Surface.bOpenXrProjectPluginEnabled
);
Surface.StatusLine = FString::Printf(
TEXT("camera %s | immersive %s | 120-cell %s | 5D %s | selectors %s | selector recall %s | XR rebinding not yet shipped"),
TEXT("camera %s | immersive %s | 120-cell owned settings %s | 5D owned settings %s | selectors %s | selector recall %s | XR rebinding not yet shipped"),
Surface.bCameraSettingsReady ? TEXT("ready") : TEXT("missing"),
Surface.bImmersivePresenceSettingsReady ? TEXT("ready") : TEXT("missing"),
Surface.bMagic120CellViewSettingsReady ? TEXT("ready") : TEXT("missing"),
Surface.bMagicCube5DViewSettingsReady ? TEXT("ready") : TEXT("missing"),
bMagic120CellOwnedSettingsReady ? TEXT("ready") : TEXT("partial"),
bMagicCube5DOwnedSettingsReady ? TEXT("ready") : TEXT("partial"),
Surface.bHigherDimensionalSelectorSettingsReady ? TEXT("ready") : TEXT("partial"),
Surface.bRepositoryBackedSelectorRecallReady ? TEXT("ready") : TEXT("unavailable")
);

View file

@ -10140,18 +10140,72 @@ struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActiveHigherDimensionalViewContextId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActiveHigherDimensionalSessionSurfaceId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString ActiveHigherDimensionalInteractiveSceneSurfaceId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Magic120CellSessionSurfaceId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Magic120CellSceneSurfaceId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Magic120CellPersistenceBoundaryId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Magic120CellStateSemanticsId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString Magic120CellViewProfileContractId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString MagicCube5DSessionSurfaceId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString MagicCube5DSceneSurfaceId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString MagicCube5DPersistenceBoundaryId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString MagicCube5DStateSemanticsId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString MagicCube5DViewProfileContractId;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 Magic120CellSelectorCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 Magic120CellProjectionSurfaceTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 Magic120CellSymmetryPresetTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 Magic120CellVisibilityPresetTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 Magic120CellFocusSurfaceTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MagicCube5DSelectorCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MagicCube5DProjectionSurfaceTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MagicCube5DStereoSurfaceTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MagicCube5DVisibilitySurfaceTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 MagicCube5DFocusSurfaceTagCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
int32 ActiveHigherDimensionalSelectorCount = 0;
@ -10167,9 +10221,15 @@ struct FHyperTwistTrainingControlSettingsOwnershipInspectSurface
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bMagic120CellViewSettingsReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bMagic120CellPersistenceSettingsReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bMagicCube5DViewSettingsReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bMagicCube5DPersistenceSettingsReady = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
bool bHigherDimensionalSelectorSettingsReady = false;

View file

@ -1320,16 +1320,95 @@ bool FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest::RunTest
Surface.CameraSettingsToolId,
TEXT("tool/camera-settings")
);
TestEqual(
TEXT("The control settings ownership surface must keep the default active higher-dimensional view context explicit when no live session is attached."),
Surface.ActiveHigherDimensionalViewContextId,
TEXT("none")
);
TestEqual(
TEXT("The control settings ownership surface must keep the default active higher-dimensional session surface explicit when no live session is attached."),
Surface.ActiveHigherDimensionalSessionSurfaceId,
TEXT("none")
);
TestEqual(
TEXT("The control settings ownership surface must keep the default active higher-dimensional interactive scene explicit when no live session is attached."),
Surface.ActiveHigherDimensionalInteractiveSceneSurfaceId,
TEXT("none")
);
TestEqual(
TEXT("The control settings ownership surface must expose the shipped Magic120Cell view profile contract id."),
Surface.Magic120CellViewProfileContractId,
TEXT("magic120cell-focus-view-profile")
);
TestTrue(
TEXT("The control settings ownership surface must expose shipped Magic120Cell persistence ownership as real structured state."),
Surface.bMagic120CellPersistenceSettingsReady
&& Surface.Magic120CellSessionSurfaceId
== TEXT("phase6c/magic120cell/dedicated-training-session-surface")
&& Surface.Magic120CellSceneSurfaceId
== TEXT("phase6c/magic120cell/interactive-scene-surface")
&& Surface.Magic120CellPersistenceBoundaryId
== TEXT("magic120cell-persistence-boundary")
&& Surface.Magic120CellStateSemanticsId
== TEXT("phase6c/magic120cell/family-owned-scene-state")
);
TestEqual(
TEXT("The control settings ownership surface must expose the current Magic120Cell projection-tag count."),
Surface.Magic120CellProjectionSurfaceTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current Magic120Cell symmetry-preset count."),
Surface.Magic120CellSymmetryPresetTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current Magic120Cell visibility-preset count."),
Surface.Magic120CellVisibilityPresetTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current Magic120Cell focus-surface count."),
Surface.Magic120CellFocusSurfaceTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the shipped MagicCube5D view profile contract id."),
Surface.MagicCube5DViewProfileContractId,
TEXT("magiccube5d-projection-view-profile")
);
TestTrue(
TEXT("The control settings ownership surface must expose shipped MagicCube5D persistence ownership as real structured state."),
Surface.bMagicCube5DPersistenceSettingsReady
&& Surface.MagicCube5DSessionSurfaceId
== TEXT("phase6c/magiccube5d/dedicated-training-session-surface")
&& Surface.MagicCube5DSceneSurfaceId
== TEXT("phase6c/magiccube5d/interactive-scene-surface")
&& Surface.MagicCube5DPersistenceBoundaryId
== TEXT("magiccube5d-persistence-boundary")
&& Surface.MagicCube5DStateSemanticsId
== TEXT("phase6c/magiccube5d/family-owned-scene-state")
);
TestEqual(
TEXT("The control settings ownership surface must expose the current MagicCube5D projection-tag count."),
Surface.MagicCube5DProjectionSurfaceTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current MagicCube5D stereo-tag count."),
Surface.MagicCube5DStereoSurfaceTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current MagicCube5D visibility-tag count."),
Surface.MagicCube5DVisibilitySurfaceTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current MagicCube5D focus-surface count."),
Surface.MagicCube5DFocusSurfaceTagCount,
5
);
TestEqual(
TEXT("The control settings ownership surface must expose the current Magic120Cell selector count."),
Surface.Magic120CellSelectorCount,
@ -1353,6 +1432,17 @@ bool FHyperTwistTrainingPanelControlSettingsOwnershipInspectSurfaceTest::RunTest
TEXT("The control settings ownership surface must retain the camera settings tool reference in its detail line."),
Surface.DetailLine.Contains(TEXT("tool/camera-settings"))
);
TestTrue(
TEXT("The control settings ownership surface detail line must now keep dedicated family session, scene, persistence, and state-semantics ids visible."),
Surface.DetailLine.Contains(TEXT("phase6c/magic120cell/dedicated-training-session-surface"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magic120cell/interactive-scene-surface"))
&& Surface.DetailLine.Contains(TEXT("magic120cell-persistence-boundary"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magic120cell/family-owned-scene-state"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magiccube5d/dedicated-training-session-surface"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magiccube5d/interactive-scene-surface"))
&& Surface.DetailLine.Contains(TEXT("magiccube5d-persistence-boundary"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magiccube5d/family-owned-scene-state"))
);
TestFalse(
TEXT("The control settings ownership surface must not fabricate repository-backed selector recall before a launch request has been observed."),
Surface.bRepositoryBackedSelectorRecallReady
@ -1438,6 +1528,13 @@ bool FHyperTwistCoachDashboardControlSettingsOwnershipInspectSurfaceTest::RunTes
Surface.DetailLine.Contains(TEXT("magic120cell-focus-view-profile"))
&& Surface.DetailLine.Contains(TEXT("magiccube5d-projection-view-profile"))
);
TestTrue(
TEXT("The coach dashboard control settings ownership surface must retain dedicated family persistence and state-semantics ids in its detail line."),
Surface.DetailLine.Contains(TEXT("magic120cell-persistence-boundary"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magic120cell/family-owned-scene-state"))
&& Surface.DetailLine.Contains(TEXT("magiccube5d-persistence-boundary"))
&& Surface.DetailLine.Contains(TEXT("phase6c/magiccube5d/family-owned-scene-state"))
);
TestTrue(
TEXT("The coach dashboard control settings ownership surface must keep the rendered disabled OpenXR project plugin truth explicit."),
Surface.DetailLine.Contains(TEXT("project OpenXR plugin not enabled"))
@ -1447,6 +1544,26 @@ bool FHyperTwistCoachDashboardControlSettingsOwnershipInspectSurfaceTest::RunTes
Surface.XrHostDecisionId,
TEXT("desktop-hosted-openxr-controller-widening-no-go")
);
TestEqual(
TEXT("The coach dashboard control settings ownership surface must preserve the shipped Magic120Cell projection-tag count."),
Surface.Magic120CellProjectionSurfaceTagCount,
5
);
TestEqual(
TEXT("The coach dashboard control settings ownership surface must preserve the shipped Magic120Cell symmetry-preset count."),
Surface.Magic120CellSymmetryPresetTagCount,
5
);
TestEqual(
TEXT("The coach dashboard control settings ownership surface must preserve the shipped MagicCube5D stereo-tag count."),
Surface.MagicCube5DStereoSurfaceTagCount,
5
);
TestEqual(
TEXT("The coach dashboard control settings ownership surface must preserve the shipped MagicCube5D focus-surface count."),
Surface.MagicCube5DFocusSurfaceTagCount,
5
);
TestFalse(
TEXT("The coach dashboard control settings ownership surface must preserve the explicit disabled OpenXR project plugin posture."),
Surface.bOpenXrProjectPluginEnabled
@ -1839,6 +1956,31 @@ bool FHyperTwistCoachDashboardControlSurfaceStructuredTextArtifactsTest::RunTest
CoachDashboard,
TEXT("CoachControlSettingsOwnershipCamera")
);
UTextBlock* ControlSettingsImmersiveTextBlock =
HyperTwistBrowserBridgeObjectTestInternal::FindDashboardTextBlock(
CoachDashboard,
TEXT("CoachControlSettingsOwnershipImmersive")
);
UTextBlock* ControlSettingsMagic120CellTextBlock =
HyperTwistBrowserBridgeObjectTestInternal::FindDashboardTextBlock(
CoachDashboard,
TEXT("CoachControlSettingsOwnershipMagic120Cell")
);
UTextBlock* ControlSettingsMagicCube5DTextBlock =
HyperTwistBrowserBridgeObjectTestInternal::FindDashboardTextBlock(
CoachDashboard,
TEXT("CoachControlSettingsOwnershipMagicCube5D")
);
UTextBlock* ControlSettingsSelectorsTextBlock =
HyperTwistBrowserBridgeObjectTestInternal::FindDashboardTextBlock(
CoachDashboard,
TEXT("CoachControlSettingsOwnershipSelectors")
);
UTextBlock* ControlSettingsSelectorRecallTextBlock =
HyperTwistBrowserBridgeObjectTestInternal::FindDashboardTextBlock(
CoachDashboard,
TEXT("CoachControlSettingsOwnershipSelectorRecall")
);
UTextBlock* ControlSettingsXrTextBlock =
HyperTwistBrowserBridgeObjectTestInternal::FindDashboardTextBlock(
CoachDashboard,
@ -1852,6 +1994,26 @@ bool FHyperTwistCoachDashboardControlSurfaceStructuredTextArtifactsTest::RunTest
TEXT("The coach dashboard must build the structured camera-settings row."),
ControlSettingsCameraTextBlock
);
TestNotNull(
TEXT("The coach dashboard must build the structured immersive-settings row."),
ControlSettingsImmersiveTextBlock
);
TestNotNull(
TEXT("The coach dashboard must build the structured Magic120Cell settings row."),
ControlSettingsMagic120CellTextBlock
);
TestNotNull(
TEXT("The coach dashboard must build the structured MagicCube5D settings row."),
ControlSettingsMagicCube5DTextBlock
);
TestNotNull(
TEXT("The coach dashboard must build the structured selector-settings row."),
ControlSettingsSelectorsTextBlock
);
TestNotNull(
TEXT("The coach dashboard must build the structured selector-recall row."),
ControlSettingsSelectorRecallTextBlock
);
TestNotNull(
TEXT("The coach dashboard must build the structured XR settings-boundary row."),
ControlSettingsXrTextBlock
@ -1872,6 +2034,60 @@ bool FHyperTwistCoachDashboardControlSurfaceStructuredTextArtifactsTest::RunTest
ControlSettingsSurface.CameraSettingsLine
);
}
if (ControlSettingsImmersiveTextBlock != nullptr)
{
TestEqual(
TEXT("The structured immersive-settings row must mirror the inspect surface."),
ControlSettingsImmersiveTextBlock->GetText().ToString(),
ControlSettingsSurface.ImmersiveSettingsLine
);
}
if (ControlSettingsMagic120CellTextBlock != nullptr)
{
TestEqual(
TEXT("The structured Magic120Cell settings row must mirror the inspect surface."),
ControlSettingsMagic120CellTextBlock->GetText().ToString(),
ControlSettingsSurface.Magic120CellSettingsLine
);
TestTrue(
TEXT("The structured Magic120Cell settings row must expose the shipped projection, symmetry, visibility, and focus counts."),
ControlSettingsMagic120CellTextBlock->GetText().ToString().Contains(TEXT("projection tags 5"))
&& ControlSettingsMagic120CellTextBlock->GetText().ToString().Contains(TEXT("symmetry presets 5"))
&& ControlSettingsMagic120CellTextBlock->GetText().ToString().Contains(TEXT("visibility presets 5"))
&& ControlSettingsMagic120CellTextBlock->GetText().ToString().Contains(TEXT("focus surfaces 5"))
);
}
if (ControlSettingsMagicCube5DTextBlock != nullptr)
{
TestEqual(
TEXT("The structured MagicCube5D settings row must mirror the inspect surface."),
ControlSettingsMagicCube5DTextBlock->GetText().ToString(),
ControlSettingsSurface.MagicCube5DSettingsLine
);
TestTrue(
TEXT("The structured MagicCube5D settings row must expose the shipped projection, stereo, visibility, and focus counts."),
ControlSettingsMagicCube5DTextBlock->GetText().ToString().Contains(TEXT("projection tags 5"))
&& ControlSettingsMagicCube5DTextBlock->GetText().ToString().Contains(TEXT("stereo tags 5"))
&& ControlSettingsMagicCube5DTextBlock->GetText().ToString().Contains(TEXT("visibility tags 5"))
&& ControlSettingsMagicCube5DTextBlock->GetText().ToString().Contains(TEXT("focus surfaces 5"))
);
}
if (ControlSettingsSelectorsTextBlock != nullptr)
{
TestEqual(
TEXT("The structured selector-settings row must mirror the inspect surface."),
ControlSettingsSelectorsTextBlock->GetText().ToString(),
ControlSettingsSurface.SelectorSettingsLine
);
}
if (ControlSettingsSelectorRecallTextBlock != nullptr)
{
TestEqual(
TEXT("The structured selector-recall row must mirror the inspect surface."),
ControlSettingsSelectorRecallTextBlock->GetText().ToString(),
ControlSettingsSurface.SelectorRecallLine
);
}
if (ControlSettingsXrTextBlock != nullptr)
{
TestEqual(

View file

@ -1189,6 +1189,98 @@ Current audit note:
- `scripts/run-hypertwist-gitnexus-status.sh`
- bounded mirror `Status: up-to-date`
## Latest dedicated-family control-settings ownership truth follow-up (`2026-06-28`)
- the next same-family native/operator truth packet then tightened the shipped
control-settings ownership seam so higher-dimensional settings proof is no
longer inferred only from broad view-profile validity:
- `FHyperTwistTrainingControlSettingsOwnershipInspectSurface` now carries
active higher-dimensional session and interactive-scene ids plus explicit
`Magic120Cell` and `MagicCube5D` dedicated-family session-surface,
interactive-scene-surface, persistence-boundary, and state-semantics ids
- the same structured state now also carries concrete family tag counts for
projection, symmetry, stereo, visibility, and focus posture plus explicit
persistence-readiness booleans
- `UHyperTwistTrainingPanelWidget::GetDisplayedControlSettingsOwnershipInspectSurface()`
now renders those exact family-owned session, scene, persistence, and
state-semantics ids into the training-panel detail lines and the active
selector-context line instead of collapsing that ownership into softer
summary text
- `HyperTwistBrowserBridgeObjectTest.cpp` now proves those exact ids and
readiness flags on both the training-panel and coach-dashboard settings
inspect seams, while the structured dashboard artifact proof also checks
the new dedicated-family persistence and state-semantics text
- the maintained Windows validation lane then proved that exact-source state
on `C:\HyperTwist_worktrees\phase10validate`:
- synced the exact touched browser test source through
`scripts/run-hypertwist-remote-windows-file-sync.sh` into the already
current maintained validation root
- remote Unreal rebuild through
`scripts/run-hypertwist-remote-unreal-build.sh`
- `Result: Succeeded`
- UnrealBuildTool `Total execution time: 168.35 seconds`
- focused remote automation then passed under:
- `HyperTwist.Browser.TrainingPanel.ControlSettingsOwnershipInspectSurface`
- `HyperTwist.Browser.CoachDashboard.ControlSettingsOwnershipInspectSurface`
- `HyperTwist.Browser.CoachDashboard.ControlSurfaceStructuredTextArtifacts`
- the accepted unattended `Failed to create the web browser window.` dialog
still appeared on the Windows editor lane, but the focused automation
proofs completed successfully and exported their reports cleanly
## Latest public-route responsive e2e hardening follow-up (`2026-06-28`)
- the next same-family public-web hardening packet then cross-referenced the
existing `FamiliarOS` and `ScriptoriumAI` website structure only for the
bounded responsive public-route proof shape, while rewriting the actual
expectations to match real HyperTwist public headings and CTAs
- HyperTwist website now owns:
- `website/playwright.config.ts`
- `website/tests/e2e/helpers/navigation.ts`
- `website/tests/e2e/responsive-public-pages.spec.ts`
- `npm --prefix website run test:e2e:responsive`
- `npm --prefix website run test:e2e:responsive:list`
- that responsive packet covers the real current HyperTwist public routes for:
- homepage
- about
- resources
- pricing
- download
- support
- register
- each route now has a browser-level proof for:
- expected public `h1` visibility
- key CTA visibility where appropriate
- no horizontal overflow on mobile and tablet viewport classes
- the owned umbrella validator now also has an opt-in browser pass:
- `scripts/run-hypertwist-web-surface-validation.sh --with-responsive-e2e`
- default validation remains unchanged so routine source/type/test lanes do
not silently start depending on Playwright browser prerequisites
## Latest protected-route responsive e2e hardening follow-up (`2026-06-28`)
- the next same-family signed-in web hardening packet then mirrored that same
bounded viewport-proof posture across the current protected operator shell
instead of leaving responsive browser proof limited to anonymous public pages
- HyperTwist website now also owns:
- `website/tests/e2e/helpers/layout.ts`
- `website/tests/e2e/responsive-protected-app-routes.spec.ts`
- `npm --prefix website run test:e2e:protected-responsive`
- `npm --prefix website run test:e2e:protected-responsive:list`
- that protected packet covers the real current signed-in routes for:
- `/app`
- `/app/launch-status`
- `/app/downloads`
- `/app/browser-access`
- `/app/account`
- `/app/notices`
- each protected route now has a browser-level proof for:
- the shared signed-in shell `h1`
- route-specific signed-in panel markers
- no horizontal overflow on mobile and tablet viewport classes
- the same umbrella validator now runs both the public and protected
responsive browser proofs when `--with-responsive-e2e` is explicitly
requested
## Latest native/public control-roster parity follow-up (`2026-06-25`)
- the same-family native/operator continuity lane then aligned the shipped

File diff suppressed because one or more lines are too long

View file

@ -126,6 +126,12 @@ proves shipped `Magic120Cell` and `MagicCube5D` host, view-context, session,
and interactive-scene ownership explicitly by activation profile id instead of
only implying readiness from broad runtime-catalog validity.
The adjacent native control-settings ownership seam was tightened the same day
too: operator-facing settings truth now proves dedicated-family session,
interactive-scene, persistence-boundary, and state-semantics ownership
explicitly for both `Magic120Cell` and `MagicCube5D` instead of leaving that
family-owned runtime state hidden behind generic view-settings wording.
Canonical audit note:
- `C:\HyperTwist\docs\ops\HYPERTWIST_UNREAL_INPUT_AND_XR_COMPLETENESS_AUDIT_2026-06-22.md`

View file

@ -4,11 +4,12 @@ set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
strict_auth_server_audit=0
skip_audits=0
with_responsive_e2e=0
usage() {
cat <<'EOF'
Usage:
scripts/run-hypertwist-web-surface-validation.sh [--strict-auth-server-audit] [--skip-audits]
scripts/run-hypertwist-web-surface-validation.sh [--strict-auth-server-audit] [--skip-audits] [--with-responsive-e2e]
Runs the current first-party HyperTwist web-surface validation packet:
- website type-check, focused tests, and production build
@ -20,6 +21,14 @@ Current auth-server nuance:
the default mode accepts the known upstream `supertokens-node -> nodemailer`
production advisory as a documented residual warning. Pass
`--strict-auth-server-audit` to fail on that residual too.
Optional responsive-browser hardening:
`--with-responsive-e2e` also runs the bounded Playwright public-route and
protected-route responsiveness packets for homepage, about, resources,
pricing, download, support, register, `/app`, `/app/launch-status`,
`/app/downloads`, `/app/browser-access`, `/app/account`, and
`/app/notices`. This expects Playwright browser prerequisites to be
available on the host.
EOF
}
@ -31,6 +40,9 @@ while [[ $# -gt 0 ]]; do
--skip-audits)
skip_audits=1
;;
--with-responsive-e2e)
with_responsive_e2e=1
;;
-h|--help)
usage
exit 0
@ -150,6 +162,14 @@ run_step \
src/__tests__/public-marketing-pages.test.tsx \
src/__tests__/public-auth-pages.test.tsx
run_step "website production build" npm --prefix website run build
if [[ "$with_responsive_e2e" -eq 1 ]]; then
run_step \
"website responsive public-route Playwright proof" \
npm --prefix website run test:e2e:responsive
run_step \
"website responsive protected-route Playwright proof" \
npm --prefix website run test:e2e:protected-responsive
fi
run_step "website/server type-check" npm --prefix website/server run type-check
run_step "website/server test suite" npm --prefix website/server test -- --run
run_step "Content/Browser shell verification" npm --prefix Content/Browser run verify:shell

View file

@ -131,6 +131,8 @@ scripts/run-hypertwist-web-surface-validation.sh
npm run type-check
npm run test
npm run build
npm run test:e2e:responsive
npm run test:e2e:protected-responsive
npm run check:runtime-readiness -- --frontend-env .env --server-env server/.env --health-url https://hypertwist.app
```
@ -164,6 +166,9 @@ upstream Radix `use client` bundler warnings so real regressions remain visible;
the one remaining accepted browser-build warning is the current upstream
`@khronosgroup/gltf-viewer` `mikktspace_bg.wasm` Vite asset-resolution message,
which does not currently break the owned shell verification or production build.
When responsive browser proof is needed too, pass
`scripts/run-hypertwist-web-surface-validation.sh --with-responsive-e2e` to
run the bounded Playwright public-route and protected-route viewport checks.
Repo-owned structural-tool posture:

View file

@ -16,6 +16,7 @@
"supertokens-auth-react": "^0.51.2"
},
"devDependencies": {
"@playwright/test": "^1.61.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
@ -600,6 +601,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/@playwright/test": {
"version": "1.61.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz",
"integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.61.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@remix-run/router": {
"version": "1.23.3",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz",
@ -2105,6 +2122,53 @@
"dev": true,
"license": "ISC"
},
"node_modules/playwright": {
"version": "1.61.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz",
"integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.61.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.61.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz",
"integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/playwright/node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/postcss": {
"version": "8.5.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",

View file

@ -10,6 +10,10 @@
"preview": "vite preview",
"type-check": "tsc --noEmit",
"test": "vitest run",
"test:e2e:responsive": "playwright test tests/e2e/responsive-public-pages.spec.ts --reporter=line",
"test:e2e:responsive:list": "playwright test tests/e2e/responsive-public-pages.spec.ts --list",
"test:e2e:protected-responsive": "playwright test tests/e2e/responsive-protected-app-routes.spec.ts --reporter=line",
"test:e2e:protected-responsive:list": "playwright test tests/e2e/responsive-protected-app-routes.spec.ts --list",
"render:sitemap": "node scripts/render-public-sitemap.mjs",
"check:runtime-readiness": "node scripts/check-runtime-readiness.mjs",
"render:same-origin-deployment": "node scripts/render-same-origin-deployment.mjs",
@ -26,6 +30,7 @@
"supertokens-auth-react": "^0.51.2"
},
"devDependencies": {
"@playwright/test": "^1.61.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",

View file

@ -0,0 +1,29 @@
import { defineConfig } from '@playwright/test'
const configuredBaseUrl = process.env.PLAYWRIGHT_BASE_URL
const baseURL = configuredBaseUrl || 'http://127.0.0.1:4173'
export default defineConfig({
testDir: 'tests/e2e',
retries: 0,
use: {
baseURL,
headless: true,
actionTimeout: 10_000,
navigationTimeout: 20_000,
viewport: { width: 1440, height: 900 },
locale: 'en-US',
timezoneId: 'UTC',
colorScheme: 'dark',
reducedMotion: 'reduce',
},
webServer: configuredBaseUrl
? undefined
: {
command: 'npm run build && npm run preview -- --host 127.0.0.1 --port 4173 --strictPort',
url: baseURL,
timeout: 180_000,
reuseExistingServer: !process.env.CI,
},
reporter: [['list']],
})

View file

@ -114,8 +114,8 @@ export const browserDesktopRealityCards = [
posture: 'Shipped today versus still gated',
description: 'HyperTwist already ships meaningful desktop control/settings ownership, but it does not market unfinished XR/controller widening as complete.',
bullets: [
'Classic keyboard, mouse/touch classic-cube control, viewer camera settings, immersive presets, and dedicated-family selector/view ownership are real today.',
'The public and protected manual already expose that shipped control roster instead of hiding it behind vague “customizable later” language.',
'Classic keyboard, mouse/touch classic-cube control, viewer camera settings, immersive presets, and dedicated-family selector, session, scene, and view ownership are real today.',
'The native operator surfaces now also expose concrete Magic120Cell and MagicCube5D session-surface, interactive-scene, persistence-boundary, and state-semantics ownership instead of hiding that proof behind softer settings summaries.',
'OpenXR/controller runtime widening and polished rebinding/preferences remain explicitly unfinished behind the current desktop-hosted No-Go boundary.',
],
action: {
@ -190,7 +190,7 @@ export const productSurfaceMatrixRows = [
description: 'This remains the real product center for training quality, packaged proof, replay, recognition, and higher-dimensional runtime ownership.',
owns: [
'Recognition, correction, replay, coaching, analytics, and packaged training behavior.',
'Dedicated-family Magic120Cell and MagicCube5D runtime-state, projection, and persistence ownership.',
'Dedicated-family Magic120Cell and MagicCube5D runtime-state, session/scene, projection, and persistence ownership.',
'The device, package, and runtime lane that public and protected browser surfaces deliberately do not absorb.',
],
doesNotClaim: [
@ -466,6 +466,7 @@ export const higherDimensionalRuntimeGuideCards = [
bullets: [
'Launch the dedicated Magic120Cell training map from the desktop runtime.',
'Use the current symmetry, focus, and logical-visibility posture as the authoritative first-party runtime owner.',
'The native operator and training surfaces now also expose the dedicated session surface, interactive-scene surface, persistence boundary, and family-owned state semantics for this lane explicitly.',
'The native operator/training surfaces can now also recall the latest persisted generated-mode selector posture for this family instead of hiding it behind the browser shell.',
'Treat the public website as documentation and rollout support, not as the runtime that executes this family.',
],
@ -476,6 +477,7 @@ export const higherDimensionalRuntimeGuideCards = [
bullets: [
'Launch the dedicated MagicCube5D training map from the desktop runtime.',
'Use the current projection-distance, stereo, and visibility defaults as the bounded first-party runtime posture.',
'The native operator and training surfaces now also expose the dedicated session surface, interactive-scene surface, persistence boundary, and family-owned state semantics for this lane explicitly.',
'The native operator/training surfaces can now also recall the latest persisted generated-mode selector posture for this family instead of forcing a blind restart.',
'Keep this lane described honestly as packaged native behavior rather than browser simulator parity.',
],
@ -507,7 +509,7 @@ export const inputAndDevicePostureCards = [
bullets: [
'Magic120Cell keeps symmetry, logical-visibility depth, and center-cell focus posture explicit.',
'MagicCube5D keeps projection-distance, stereo, face-visibility, and focus posture explicit.',
'The desktop operator/training lane now also surfaces these dedicated-family view owners together with current camera-settings ownership.',
'The desktop operator and training lane now also surfaces these dedicated-family view owners together with exact session-surface, interactive-scene, persistence-boundary, and state-semantics ownership.',
'The same native surfaces now expose selector recall from the latest persisted generated-mode launch request when that launch history exists.',
'These controls belong to the dedicated-family desktop runtime lanes, not to the public website.',
],
@ -575,6 +577,7 @@ export const controlProfileRosterCards = [
'The current scenic immersive roster includes 3 immersive-intensity presets and 3 reduced-distraction presets.',
'Magic120Cell currently exposes 4 selector options alongside its symmetry, focus, and visibility owners.',
'MagicCube5D currently exposes 4 selector options alongside its projection-distance, stereo, focus, and visibility owners.',
'Both higher-dimensional families now also surface their dedicated session, interactive-scene, persistence-boundary, and state-semantics ownership directly in the native diagnostics lane.',
],
},
{
@ -582,6 +585,7 @@ export const controlProfileRosterCards = [
description: 'Current continuity is real, but it is still narrower than a finished global preferences and controller-rebinding suite.',
bullets: [
'The native operator and training surfaces can recall the latest persisted generated-mode selector posture when a structurally valid launch request exists.',
'Those same native surfaces now also prove which family-specific persistence boundary and state-semantics contract currently owns the higher-dimensional settings lane.',
'Viewer camera settings and immersive-presence settings are already first-party owned in the desktop runtime.',
'Finished headset-specific controller rebinding and broad VR onboarding remain outside the current desktop-hosted No-Go lane unless a later reopen proves the need.',
],
@ -1025,6 +1029,11 @@ export const changelogEntries = [
title: 'Public pages now explain what each route is actually for',
details: 'The homepage, docs, and resources routes now share a first-party public route atlas explaining what each major public page owns: product truth, onboarding, launch readiness, pricing, download, support, release notes, and the legal/distribution surfaces are now easier to navigate as one professional operator manual instead of a flatter marketing shell.',
},
{
date: 'June 28, 2026',
title: 'Native higher-dimensional settings proof now exposes family session and persistence seams',
details: 'The desktop operator and training diagnostics now render exact Magic120Cell and MagicCube5D session-surface, interactive-scene, persistence-boundary, and state-semantics ownership instead of only broad view-profile wording, and the maintained Windows validation lane re-exported focused browser proof green for the training-panel, coach-dashboard, and structured dashboard settings seams.',
},
{
date: 'June 27, 2026',
title: 'Protected launch status now has its own signed-in authority route',
@ -1168,7 +1177,7 @@ export const changelogEntries = [
{
date: 'June 24, 2026',
title: 'Signed-in operator shell now mirrors the native control roster',
details: 'The protected dashboard, browser-access, and account routes now carry the same shipped desktop control/settings roster exposed by the public manual, including the classic-wca-keyboard/v1 profile, scenic immersive presets, dedicated-family selector/view ownership, selector-recall continuity, and the explicit unfinished XR/controller boundary.',
details: 'The protected dashboard, browser-access, and account routes now carry the same shipped desktop control/settings roster exposed by the public manual, including the classic-wca-keyboard/v1 profile, scenic immersive presets, dedicated-family selector/view ownership, selector-recall continuity, later dedicated-family session/scene/persistence proof, and the explicit unfinished XR/controller boundary.',
},
{
date: 'June 24, 2026',
@ -1270,7 +1279,7 @@ export const supportFaqs = [
},
{
question: 'Can I already customize controls and higher-dimensional view posture?',
answer: 'Partly. The current desktop runtime already owns the classic keyboard profile, viewer camera settings, immersive-presence settings, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults, and the native operator surfaces can now recall selector posture from the latest persisted generated-mode launch request. A broader polished controller rebinding and preferences layer remains outside the current desktop-hosted No-Go lane unless a later reopen proves the need.',
answer: 'Partly. The current desktop runtime already owns the classic keyboard profile, viewer camera settings, immersive-presence settings, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults. The native operator surfaces now also expose which Magic120Cell or MagicCube5D session surface, interactive scene, persistence boundary, and state-semantics contract currently owns that settings lane, and they can recall selector posture from the latest persisted generated-mode launch request. A broader polished controller rebinding and preferences layer remains outside the current desktop-hosted No-Go lane unless a later reopen proves the need.',
},
{
question: 'Do higher-dimensional selector choices persist between sessions?',

View file

@ -152,6 +152,14 @@ img {
justify-content: center;
}
.button-row {
flex-wrap: wrap;
}
.button-row > * {
min-width: 0;
}
.site-nav__link,
.app-nav__link {
padding: 0.7rem 0.95rem;
@ -246,6 +254,8 @@ img {
.auth-card__subtitle {
color: var(--ht-muted);
line-height: 1.7;
overflow-wrap: anywhere;
word-break: break-word;
}
.hero-panel,
@ -350,6 +360,7 @@ img {
.surface-matrix > *,
.panel-grid > * {
flex: 1 1 280px;
min-width: 0;
}
.card,
@ -428,6 +439,12 @@ img {
color: var(--ht-muted);
}
.list li,
.auth-card__footer {
overflow-wrap: anywhere;
word-break: break-word;
}
.feature-band {
flex-wrap: wrap;
}

View file

@ -0,0 +1,12 @@
import { expect, type Page } from '@playwright/test'
export async function expectNoHorizontalOverflow(page: Page) {
const metrics = await page.evaluate(() => ({
documentWidth: document.documentElement.scrollWidth,
viewportWidth: document.documentElement.clientWidth,
bodyWidth: document.body.scrollWidth,
}))
expect(metrics.documentWidth).toBeLessThanOrEqual(metrics.viewportWidth + 1)
expect(metrics.bodyWidth).toBeLessThanOrEqual(metrics.viewportWidth + 1)
}

View file

@ -0,0 +1,50 @@
import type { Page } from '@playwright/test'
type WaitUntilState = 'load' | 'domcontentloaded' | 'networkidle' | 'commit'
type RouteNavigationOptions = {
waitUntil?: WaitUntilState
timeoutMs?: number
}
const PLATFORM_AUTH_STORAGE_KEY = 'hypertwist.platform.user.v1'
const E2E_FALLBACK_USER = {
id: 'e2e_operator_user',
name: 'E2E Operator',
email: 'e2e.operator@hypertwist.local',
authMethod: 'email',
plan: 'free',
}
async function seedFallbackAuthForProtectedRoutes(page: Page) {
await page.addInitScript(
({ storageKey, userJson }) => {
try {
if (!window.localStorage.getItem(storageKey)) {
window.localStorage.setItem(storageKey, userJson)
}
} catch {
// Fail-open for storage-restricted contexts.
}
},
{
storageKey: PLATFORM_AUTH_STORAGE_KEY,
userJson: JSON.stringify(E2E_FALLBACK_USER),
},
)
}
export async function gotoAppRoute(
page: Page,
routePath: string,
options: RouteNavigationOptions = {},
) {
const normalizedPath = routePath.startsWith('/') ? routePath : `/${routePath}`
if (normalizedPath.startsWith('/app')) {
await seedFallbackAuthForProtectedRoutes(page)
}
await page.goto(normalizedPath, {
waitUntil: options.waitUntil ?? 'domcontentloaded',
timeout: options.timeoutMs ?? 30_000,
})
}

View file

@ -0,0 +1,63 @@
import { expect, test, type Page } from '@playwright/test'
import { gotoAppRoute } from './helpers/navigation'
import { expectNoHorizontalOverflow } from './helpers/layout'
type ProtectedRouteExpectation = {
path: string
marker: string
}
const responsiveProtectedRoutes: readonly ProtectedRouteExpectation[] = [
{
path: '/app',
marker: 'Desktop-link pairing',
},
{
path: '/app/launch-status',
marker: 'Protected launch status',
},
{
path: '/app/downloads',
marker: 'Release targets',
},
{
path: '/app/browser-access',
marker: 'Current browser posture',
},
{
path: '/app/account',
marker: 'Session profile',
},
{
path: '/app/notices',
marker: 'Distribution notices',
},
] as const
async function assertResponsiveProtectedRoute(page: Page, route: ProtectedRouteExpectation) {
await gotoAppRoute(page, route.path, { waitUntil: 'domcontentloaded', timeoutMs: 45_000 })
await expect(page.getByRole('heading', { level: 1, name: 'HyperTwist dashboard' })).toBeVisible()
await expect(page.getByText(route.marker, { exact: true }).first()).toBeVisible()
await expectNoHorizontalOverflow(page)
}
test.describe('responsive protected app routes (mobile)', () => {
test.use({ viewport: { width: 390, height: 844 } })
for (const route of responsiveProtectedRoutes) {
test(`${route.path} renders without horizontal overflow`, async ({ page }) => {
await assertResponsiveProtectedRoute(page, route)
})
}
})
test.describe('responsive protected app routes (tablet)', () => {
test.use({ viewport: { width: 820, height: 1180 } })
for (const route of responsiveProtectedRoutes) {
test(`${route.path} renders without horizontal overflow`, async ({ page }) => {
await assertResponsiveProtectedRoute(page, route)
})
}
})

View file

@ -0,0 +1,78 @@
import { expect, test, type Page } from '@playwright/test'
import { gotoAppRoute } from './helpers/navigation'
import { expectNoHorizontalOverflow } from './helpers/layout'
type PublicRouteExpectation = {
path: string
heading: string
cta?: string
}
const responsivePublicRoutes: readonly PublicRouteExpectation[] = [
{
path: '/',
heading: 'HyperTwist turns cube practice into a real operator-grade training stack.',
cta: 'Download desktop app',
},
{
path: '/about',
heading: 'A training stack serious enough for higher-dimensional cubing.',
},
{
path: '/resources',
heading: 'Resources that explain the product without leaking operator-only internals.',
},
{
path: '/pricing',
heading: 'Pricing that matches the actual delivery model.',
},
{
path: '/download',
heading: 'Download the desktop build and pair it with your browser account.',
},
{
path: '/support',
heading: 'Support for rollout, downloads, pricing, and browser-to-desktop access.',
},
{
path: '/register',
heading: 'Create a HyperTwist account',
cta: 'Create account',
},
] as const
async function assertResponsivePublicRoute(page: Page, route: PublicRouteExpectation) {
await gotoAppRoute(page, route.path, { waitUntil: 'domcontentloaded', timeoutMs: 45_000 })
await expect(page.getByRole('heading', { level: 1, name: route.heading })).toBeVisible()
if (route.cta) {
const button = page.getByRole('button', { name: route.cta })
if ((await button.count()) > 0) {
await expect(button.first()).toBeVisible()
} else {
await expect(page.getByRole('link', { name: route.cta }).first()).toBeVisible()
}
}
await expectNoHorizontalOverflow(page)
}
test.describe('responsive public routes (mobile)', () => {
test.use({ viewport: { width: 390, height: 844 } })
for (const route of responsivePublicRoutes) {
test(`${route.path} renders without horizontal overflow`, async ({ page }) => {
await assertResponsivePublicRoute(page, route)
})
}
})
test.describe('responsive public routes (tablet)', () => {
test.use({ viewport: { width: 820, height: 1180 } })
for (const route of responsivePublicRoutes) {
test(`${route.path} renders without horizontal overflow`, async ({ page }) => {
await assertResponsivePublicRoute(page, route)
})
}
})