fix(streaming): block login on complete world reveal

Make initial login and portal arrival consume one WorldRevealReadinessBarrier that joins near-tier mesh publication, destination composite uploads, and collision residency before normal world geometry becomes visible. This ports retail SmartBox's blocking-cell completion edge into the asynchronous client instead of exposing a ground-only login.

Add focused outdoor, indoor, texture, and invalid-claim tests; update the retail pseudocode, architecture, divergence record, issue ledger, roadmap baseline, and synchronized agent guidance.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-20 16:08:03 +02:00
parent 6c3bd4ce4b
commit b60cb67009
14 changed files with 360 additions and 102 deletions

View file

@ -64,7 +64,7 @@ sequence without advancing time and republish all part transforms. Forcing a
Ready motion, recognizing recall by id, or freezing the previously published
part pose would all diverge from this general retail mechanism.
## 2. Portal exit waits for render publication as well as collision data
## 2. Login and portal exit wait for render publication as well as collision data
Named retail references:
@ -82,6 +82,15 @@ that teleport is no longer in progress,
`EndTeleportAnimation` begins `TAS_TUNNEL_CONTINUE`; the normal world is not
revealed before the blocking load edge has completed.
The same `SmartBox::UseTime` edge governs initial position completion. It does
not distinguish “enough collision to stand” from “enough render state to show
the world”: while `CellManager::blocking_for_cells` is set it only checks
prefetch status, and only after the block clears does it change the player's
position, set `position_update_complete`, advance object/physics/landscape
time, and draw the normal scene. Therefore acdream's login auto-entry cannot
gate on one sampled terrain height while portal arrival uses a complete render
barrier. Both presentations must consume one shared asynchronous equivalent.
acdream's load is split into two independent readiness domains:
```text
@ -98,18 +107,28 @@ worker/register path
Required asynchronous equivalent:
```text
TeleportWorldReady(destination):
WorldRevealReady(destination):
if destination claim cannot be hydrated:
return true so the existing loud forced-placement path diagnoses it
if destination is indoor:
return render center landblock Near-tier and ready
AND destination composite textures ready
AND destination EnvCell collision data ready
return every landblock in the priority near ring Near-tier and render-ready
AND destination composite textures ready
AND every landblock in that ring collision-resident
```
`WorldRevealReadinessBarrier.Begin` invalidates destination-scoped composite
readiness for both the first accepted player position and each accepted portal
destination. After the render-thread mesh tick, `Prepare` advances composite
uploads only when the required static meshes are published. Login remains
behind its sky-only render gate and portal travel remains in its tunnel until
the same `IsReady` predicate opens. This prevents the two paths from drifting
apart again while preserving their different presentations.
Streaming completion is generation- and tier-aware. Every hard recenter,
dungeon collapse, and dungeon expansion advances a token carried by Load,
Promote, Unload, and their results. This rejects an old build even when its id