Capture browser runtime ready payload

This commit is contained in:
axiomlogicnexus 2026-06-19 05:35:38 +00:00
parent 8704e0976d
commit 37eb22040c
12 changed files with 285 additions and 1 deletions

View file

@ -26,6 +26,17 @@ namespace HyperTwistBrowserBridgeObjectInternal
&& FJsonObjectConverter::JsonObjectStringToUStruct(Json, &OutEnvelope, 0, 0)
&& OutEnvelope.IsStructurallyValid();
}
bool TryCacheRuntimeReadyPayload(
const FString& Json,
FHyperTwistBrowserRuntimeReadyPayload& OutPayload
)
{
OutPayload = FHyperTwistBrowserRuntimeReadyPayload();
return !Json.IsEmpty()
&& FJsonObjectConverter::JsonObjectStringToUStruct(Json, &OutPayload, 0, 0)
&& OutPayload.IsStructurallyValid();
}
}
void UHyperTwistBrowserBridgeObject::NotifyEnvelope(const FString& EnvelopeJson)
@ -59,6 +70,17 @@ void UHyperTwistBrowserBridgeObject::NotifyState(const FString& StateJson)
void UHyperTwistBrowserBridgeObject::NotifyRuntimeReady(const FString& RuntimeReadyJson)
{
LastRuntimeReadyJson = RuntimeReadyJson;
FHyperTwistBrowserRuntimeReadyPayload RuntimeReadyPayload;
if (HyperTwistBrowserBridgeObjectInternal::TryCacheRuntimeReadyPayload(
RuntimeReadyJson,
RuntimeReadyPayload
))
{
LastRuntimeReadyPayload = RuntimeReadyPayload;
bHasLastRuntimeReadyPayload = true;
}
OnRuntimeReady.Broadcast(RuntimeReadyJson);
}
@ -69,9 +91,11 @@ void UHyperTwistBrowserBridgeObject::ResetReceivedMessages()
LastRuntimeReadyJson.Reset();
LastTilingEnvelope = FHyperTwistTrainingTilingStateEnvelope();
LastTilingStateEnvelope = FHyperTwistTrainingTilingStateEnvelope();
LastRuntimeReadyPayload = FHyperTwistBrowserRuntimeReadyPayload();
LastBrowserRuntimeStatusEnvelope = FHyperTwistBrowserRuntimeStatusEnvelope();
bHasLastTilingEnvelope = false;
bHasLastTilingStateEnvelope = false;
bHasLastRuntimeReadyPayload = false;
bHasLastBrowserRuntimeStatusEnvelope = false;
}
@ -85,6 +109,16 @@ bool UHyperTwistBrowserBridgeObject::TryGetLastTilingEnvelope(
return bHasLastTilingEnvelope;
}
bool UHyperTwistBrowserBridgeObject::TryGetLastRuntimeReadyPayload(
FHyperTwistBrowserRuntimeReadyPayload& OutRuntimeReadyPayload
) const
{
OutRuntimeReadyPayload = bHasLastRuntimeReadyPayload
? LastRuntimeReadyPayload
: FHyperTwistBrowserRuntimeReadyPayload();
return bHasLastRuntimeReadyPayload;
}
bool UHyperTwistBrowserBridgeObject::TryGetLastTilingStateEnvelope(
FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
) const

View file

@ -129,6 +129,15 @@ bool UHyperTwistBrowserWidget::TryGetLastTilingEnvelope(
&& BrowserBridgeObject->TryGetLastTilingEnvelope(OutStateEnvelope);
}
bool UHyperTwistBrowserWidget::TryGetLastRuntimeReadyPayload(
FHyperTwistBrowserRuntimeReadyPayload& OutRuntimeReadyPayload
) const
{
OutRuntimeReadyPayload = FHyperTwistBrowserRuntimeReadyPayload();
return BrowserBridgeObject != nullptr
&& BrowserBridgeObject->TryGetLastRuntimeReadyPayload(OutRuntimeReadyPayload);
}
bool UHyperTwistBrowserWidget::TryGetLastTilingStateEnvelope(
FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
) const

View file

@ -7,6 +7,39 @@
DECLARE_MULTICAST_DELEGATE_OneParam(FHyperTwistBrowserRuntimeReadyDelegate, const FString&);
USTRUCT(BlueprintType)
struct FHyperTwistBrowserRuntimeReadyPayload
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
FString Status;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
FString Runtime;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
FString Mode;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
int32 AdapterCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
FString ShellAuthority;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
int32 QueuedCommandCountAtRuntimeReady = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
int32 QueuedShellStateCountAtRuntimeReady = 0;
bool IsStructurallyValid() const
{
return Status.Equals(TEXT("ready"), ESearchCase::CaseSensitive)
&& !Runtime.IsEmpty() && !Mode.IsEmpty();
}
};
USTRUCT(BlueprintType)
struct FHyperTwistBrowserRuntimeStatusSnapshot
{
@ -104,6 +137,11 @@ public:
FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
bool TryGetLastRuntimeReadyPayload(
FHyperTwistBrowserRuntimeReadyPayload& OutRuntimeReadyPayload
) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
bool TryGetLastTilingStateEnvelope(
FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
@ -137,6 +175,12 @@ public:
UPROPERTY(Transient)
bool bHasLastTilingStateEnvelope = false;
UPROPERTY(Transient)
FHyperTwistBrowserRuntimeReadyPayload LastRuntimeReadyPayload;
UPROPERTY(Transient)
bool bHasLastRuntimeReadyPayload = false;
UPROPERTY(Transient)
FHyperTwistBrowserRuntimeStatusEnvelope LastBrowserRuntimeStatusEnvelope;

View file

@ -61,6 +61,11 @@ public:
FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
bool TryGetLastRuntimeReadyPayload(
FHyperTwistBrowserRuntimeReadyPayload& OutRuntimeReadyPayload
) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
bool TryGetLastTilingStateEnvelope(
FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope

View file

@ -131,6 +131,72 @@ bool FHyperTwistBrowserBridgeObjectRuntimeReadyDelegateTest::RunTest(const FStri
return true;
}
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FHyperTwistBrowserBridgeObjectRuntimeReadyPayloadDecodeTest,
"HyperTwist.Browser.Bridge.RuntimeReadyPayloadDecode",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)
bool FHyperTwistBrowserBridgeObjectRuntimeReadyPayloadDecodeTest::RunTest(
const FString& Parameters
)
{
UHyperTwistBrowserBridgeObject* BridgeObject = NewObject<UHyperTwistBrowserBridgeObject>();
TestNotNull(TEXT("The browser bridge object must be constructible."), BridgeObject);
if (BridgeObject == nullptr)
{
return false;
}
const FString RuntimeReadyJson =
TEXT("{\"status\":\"ready\",\"runtime\":\"hypertwist-browser-runtime\",")
TEXT("\"mode\":\"bundled-module\",\"adapterCount\":21,")
TEXT("\"shellAuthority\":\"Content/Browser/index.html\",")
TEXT("\"queuedCommandCountAtRuntimeReady\":2,")
TEXT("\"queuedShellStateCountAtRuntimeReady\":1}");
BridgeObject->NotifyRuntimeReady(RuntimeReadyJson);
FHyperTwistBrowserRuntimeReadyPayload RuntimeReadyPayload;
TestTrue(
TEXT("The browser bridge object must decode a typed runtime-ready payload."),
BridgeObject->TryGetLastRuntimeReadyPayload(RuntimeReadyPayload)
);
TestEqual(
TEXT("The typed runtime-ready payload must preserve the ready status."),
RuntimeReadyPayload.Status,
TEXT("ready")
);
TestEqual(
TEXT("The typed runtime-ready payload must preserve the runtime id."),
RuntimeReadyPayload.Runtime,
TEXT("hypertwist-browser-runtime")
);
TestEqual(
TEXT("The typed runtime-ready payload must preserve the runtime mode."),
RuntimeReadyPayload.Mode,
TEXT("bundled-module")
);
TestEqual(
TEXT("The typed runtime-ready payload must preserve the adapter count."),
RuntimeReadyPayload.AdapterCount,
21
);
TestEqual(
TEXT("The typed runtime-ready payload must preserve the queued shell-state count."),
RuntimeReadyPayload.QueuedShellStateCountAtRuntimeReady,
1
);
BridgeObject->ResetReceivedMessages();
TestFalse(
TEXT("Resetting the bridge object must also clear the typed runtime-ready payload cache."),
BridgeObject->TryGetLastRuntimeReadyPayload(RuntimeReadyPayload)
);
return true;
}
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
FHyperTwistBrowserBridgeObjectTilingStateEnvelopeDecodeTest,
"HyperTwist.Browser.Bridge.TilingStateEnvelopeDecode",

View file

@ -0,0 +1,101 @@
# HyperTwist Phase 8A browser runtime-ready native-capture implementation packet
Created on `2026-06-19`
## Status
- first-party HyperTwist packet
- bounded first-party `Phase 8A` continuation slice
## Purpose
This packet hardens the already-landed embedded browser shipping lane directly
at the original runtime-ready handshake.
The landed slice is:
- decode first-party `hypertwist-runtime-ready` payloads into typed
Unreal-owned structs instead of leaving the handshake as raw JSON only
- retain the last valid runtime-ready payload through
`UHyperTwistBrowserBridgeObject` and `UHyperTwistBrowserWidget`
- preserve the existing flush behavior so the browser-ready event still marks
the widget ready and flushes queued shell traffic exactly as before
- widen focused browser automation with a dedicated typed runtime-ready decode
test on the primary reverse-SSH Windows lane
It is not:
- a topology widening into the optional full-browser client branch
- a renderer-port packet
- a rewrite of the existing embedded-browser queue/flush posture
## Current authority basis
This implementation packet stands on:
- `docs/ops/HYPERTWIST_COMPREHENSIVE_RECONSTRUCTION_ROADMAP_2026-06-10.md`
- `docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md`
- `docs/v6_5_deep_manual_pack/HyperTwist/FEATURE_REGISTRY.md`
- `docs/v6_5_deep_manual_pack/HyperTwist/ARCHITECTURE.md`
- `docs/arch/HYPERTWIST_PHASE8A_BROWSER_RUNTIME_STATUS_NATIVE_CAPTURE_IMPLEMENTATION_PACKET_2026-06-19.md`
## Landed scope
Current code now hardens the live embedded-browser lane through:
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistBrowser/HyperTwistBrowserBridgeObject.h`
typed first-party `FHyperTwistBrowserRuntimeReadyPayload` ownership
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBrowser/HyperTwistBrowserBridgeObject.cpp`
typed decode and retained caching for the browser runtime-ready payload
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistBrowser/HyperTwistBrowserWidget.h`
and
`UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBrowser/HyperTwistBrowserWidget.cpp`
widget-level forwarding for the retained typed runtime-ready payload
- focused browser automation in
`UnrealHyperTwist/Source/UnrealHyperTwist/Tests/HyperTwistBrowserBridgeObjectTest.cpp`
for the new:
- `Bridge.RuntimeReadyPayloadDecode`
## Why this hardening mattered
The shipping lane already had a real runtime-ready handshake, but the native
host still treated its payload as an opaque string even after the later
runtime-status ownership seam landed.
That left the initial browser-ready authority handoff weaker than the adjacent
typed ownership surfaces. This packet closes that gap while keeping the
existing startup queue and flush behavior intact.
## Validation
Local validation:
- `git diff --check`
- result on `2026-06-19`: passed
Windows build validation:
- `Build.bat UnrealHyperTwistEditor Win64 Development -Project='C:\HyperTwist_worktrees\phase10validate\UnrealHyperTwist\UnrealHyperTwist.uproject' -WaitMutex -NoHotReloadFromIDE -NoUba`
- result on `2026-06-19`: `Result: Succeeded` with UnrealBuildTool
`Total execution time: 88.20 seconds` on isolated worktree
`C:\HyperTwist_worktrees\phase10validate`
Focused browser validation:
- `Automation RunTests HyperTwist.Browser`
- result on `2026-06-19`: found `9` `HyperTwist.Browser.*` tests and passed
all `9`, exporting the report to
`Saved\AutomationReports\Browser-RuntimeReadyPayload-Verify`, including the
new:
- `Bridge.RuntimeReadyPayloadDecode`
## Product effect
This packet keeps the live embedded browser/CEF shipping lane intact, but it
upgrades the original handshake seam:
- Unreal now retains a typed runtime-ready payload instead of only raw JSON
- the ready-handshake facts can be reused from native code and diagnostics
without reparsing ad hoc strings
- queue flush behavior remains unchanged while the authority seam underneath it
becomes more explicit

View file

@ -103,3 +103,10 @@ upgrades native ownership quality:
until explicit reset
- the embedded browser lane becomes easier to reason about from Unreal-side
code and future diagnostics without widening into a browser-first topology
Follow-on continuation:
- `docs/arch/HYPERTWIST_PHASE8A_BROWSER_RUNTIME_READY_NATIVE_CAPTURE_IMPLEMENTATION_PACKET_2026-06-19.md`
now records the adjacent typed native capture seam for the original
`hypertwist-runtime-ready` handshake payload, so the ready-authority handoff
is no longer raw JSON only either.

View file

@ -427,6 +427,8 @@ Closure read:
- Validation evidence on `2026-06-19`: local `npm --prefix Content/Browser run verify:shell` passed and `npm --prefix Content/Browser run build` succeeded, then the primary reverse-SSH `localhost:22022` lane rebuilt isolated worktree `C:\HyperTwist_worktrees\phase10validate` with `Result: Succeeded` and UnrealBuildTool `Total execution time: 160.16 seconds`, and `Automation RunTests HyperTwist.Browser` found `7` `HyperTwist.Browser.*` tests and passed all `7` at `Saved\AutomationReports\Browser-StatusSurface-Verify`
- Native-capture continuation on `2026-06-19`: current code now closes the remaining authority gap below that status surface by decoding first-party `browser-runtime-status` envelopes into typed Unreal-owned structs, retaining the last valid runtime-status snapshot through `UHyperTwistBrowserBridgeObject` and `UHyperTwistBrowserWidget`, and preserving that snapshot across later unrelated envelope traffic until explicit reset
- Validation evidence on `2026-06-19`: the same primary reverse-SSH `localhost:22022` lane rebuilt isolated worktree `C:\HyperTwist_worktrees\phase10validate` with `Result: Succeeded` and UnrealBuildTool `Total execution time: 111.69 seconds`, then `Automation RunTests HyperTwist.Browser` found `8` `HyperTwist.Browser.*` tests and passed all `8` at `Saved\AutomationReports\Browser-RuntimeStatusNativeCapture-Verify`
- Runtime-ready continuation on `2026-06-19`: current code now closes the adjacent handshake gap as well by decoding first-party `hypertwist-runtime-ready` payloads into typed Unreal-owned structs, retaining the last valid runtime-ready payload through `UHyperTwistBrowserBridgeObject` and `UHyperTwistBrowserWidget`, and keeping the existing browser-ready queue-flush behavior intact
- Validation evidence on `2026-06-19`: the same primary reverse-SSH `localhost:22022` lane rebuilt isolated worktree `C:\HyperTwist_worktrees\phase10validate` with `Result: Succeeded` and UnrealBuildTool `Total execution time: 88.20 seconds`, then `Automation RunTests HyperTwist.Browser` found `9` `HyperTwist.Browser.*` tests and passed all `9` at `Saved\AutomationReports\Browser-RuntimeReadyPayload-Verify`
### 8B — State Synchronization
- [x] Bridge UE cube state to browser via embedded Unreal bridge object plus JavaScript `postMessage` fallback

View file

@ -137,6 +137,10 @@ Use these as the current governing docs:
`browser-runtime-status` capture seam through the browser bridge/widget,
retaining the last valid runtime snapshot across unrelated later envelope
traffic until explicit reset
- that same shipping/browser posture now also has a typed Unreal-side
`hypertwist-runtime-ready` capture seam through the browser bridge/widget,
keeping the existing queue-flush behavior intact while lifting the original
runtime-ready handshake out of raw JSON-only handling
- `MagicTile` `Phase 7C` is now landed separately through the bundled tiling native-behavior
proof contract/probe seam, runtime-library proof helpers, and focused Windows validation on
isolated worktree `C:\HyperTwist_worktrees\phase10validate`

View file

@ -105,6 +105,12 @@ browser bridge now decodes and retains typed first-party
snapshot the browser shell projects, and preserves the last valid snapshot
across later unrelated envelope traffic until explicit reset.
That same shipping lane was then hardened once more on `2026-06-19`: the
native browser bridge now also decodes and retains the typed first-party
`hypertwist-runtime-ready` handshake payload, so the original browser-ready
authority seam is no longer raw JSON only even though the existing queue flush
behavior remains unchanged.
The optional full-browser client path now exists only as a spec-defined
first-party branch:

View file

@ -144,7 +144,7 @@ Do not collapse those three tiers into one undifferentiated "features" voice.
| First-party provider-neutral custom-endpoint runtime routing | Implemented now | landed first-party `Phase 6R-AI` | First-party per-session provider-profile endpoint selection, runtime routing, fallback-health reflection, and bounded provider-backed transport-failure posture are now live above the landed provider-profile/BYOK and provider-routing seams. Provider-specific overlays, payment execution, provider-portal ownership, and payload shipping remain deferred. |
| Analytics/reporting surfaces | Implemented now | landed analytics/reporting packets | Reporting is real, but bounded to accepted retained slices. |
| Rewritten training analytics and report reference grounding | Implemented now | `apache/echarts` retained permissive lane + first-party current code | Current live `Training Analytics` reference side includes four rewritten first-party targets grounded in retained `apache/echarts`: session outcome and progress reporting, analytics data-view and export, timing-trend history and overview interaction, and the optional richer explainer or sidecar boundary. This does not displace the landed `Phase 3R-C` first-party analytics/reporting owner or elevate `ecomfe/echarts-gl` and `ecomfe/zrender` beyond support-only sidecars. |
| Browser/spatial/media adjunct surfaces | Implemented now | landed `three.js`, `react-three-fiber`, `xr`, `model-viewer`, `remotion` packets | These are implemented bounded families, and the current Phase 1 browser-runtime landing now includes a first-party authoritative `Content/Browser/index.html` shell, bundled-runtime upgrade path, committed clean-checkout plain-JS fallback runtime, embedded `UHyperTwistBrowserWidget` bridge, the `2026-06-19` runtime-ready queue hardening that retains outbound Unreal shell traffic until the browser runtime is ready, a same-day first-party `Browser Runtime Status` surface with shared boot-state ownership across bundled and fallback shells, and a follow-on typed Unreal-side `browser-runtime-status` capture seam that retains the last valid runtime snapshot across unrelated later envelope traffic until explicit reset. This still is not proof of unlimited browser-shell parity. |
| Browser/spatial/media adjunct surfaces | Implemented now | landed `three.js`, `react-three-fiber`, `xr`, `model-viewer`, `remotion` packets | These are implemented bounded families, and the current Phase 1 browser-runtime landing now includes a first-party authoritative `Content/Browser/index.html` shell, bundled-runtime upgrade path, committed clean-checkout plain-JS fallback runtime, embedded `UHyperTwistBrowserWidget` bridge, the `2026-06-19` runtime-ready queue hardening that retains outbound Unreal shell traffic until the browser runtime is ready, a same-day first-party `Browser Runtime Status` surface with shared boot-state ownership across bundled and fallback shells, a follow-on typed Unreal-side `browser-runtime-status` capture seam that retains the last valid runtime snapshot across unrelated later envelope traffic until explicit reset, and a second follow-on typed Unreal-side `hypertwist-runtime-ready` capture seam that raises the original handshake payload out of raw JSON-only handling without changing queue flush behavior. This still is not proof of unlimited browser-shell parity. |
| Optional full-browser client path above Unreal backend authority | Deep-source grounded retained | landed first-party `Phase 8B` preparation packet + spec/evidence continuation | This branch remains a spec-only first-party option: a browser-owned rendering and input shell may sit above explicit Unreal backend seams while Unreal remains authoritative for puzzle, training, timer, replay, and persistence state. The current continuation now fixes the allowed seam families to catalog, session, action, state, continuity push, replay, persistence status, and runtime health, while keeping offline-first, public-hosted, and native renderer widening posture deferred. The landed embedded browser/CEF shell remains the current shipping posture, and this branch stays separate from any native `MagicTile` behavior or renderer widening. |
| Rewritten browser spatial scene and renderer reference grounding | Implemented now | `mrdoob/three.js` retained permissive lane + first-party current code | Current live `Browser 3D and XR Support` reference side includes one rewritten first-party target grounded in retained `mrdoob/three.js`: the browser spatial scene and renderer contract. This does not displace the landed `Phase 3R-F` first-party browser spatial owner trio or absorb the adjacent `react-three-fiber` renderer-bridge and `xr` session slices. |
| Rewritten React-side browser renderer and event-bridge grounding | Implemented now | `pmndrs/react-three-fiber` retained permissive lane + first-party current code | Current live `Browser 3D and XR Support` reference side includes one rewritten first-party target grounded in retained `react-three-fiber`: the React scene renderer and event bridge. This does not displace the landed `Phase 3R-F` first-party browser spatial owner trio or absorb the adjacent `three.js` scene substrate and `xr` session slices. |

View file

@ -129,6 +129,12 @@ Current consolidated milestone snapshot:
envelope traffic until explicit reset, with refreshed primary-lane
`localhost:22022` validation at `8` green `HyperTwist.Browser.*` tests
including the hardened `Bridge.RuntimeStatusEnvelopeDecode`
- the same embedded-browser lane then gained typed native Unreal ownership of
the original `hypertwist-runtime-ready` handshake payload on `2026-06-19`,
keeping the queue flush behavior intact while raising that authority seam out
of raw JSON-only handling, with refreshed primary-lane `localhost:22022`
validation at `9` green `HyperTwist.Browser.*` tests including the new
`Bridge.RuntimeReadyPayloadDecode`
- classic-cube `Phase 9A` replay recording is now closed through first-party
runtime capture, `.json` replay persistence, local playback reconstruction,
schema-light replay normalization across save/load/viewer import, and live