Repository navigation
1.54.3 — stability patch (54-int) - #522
Merged
Merged
Conversation
… chip only
A pinch while measuring showed its own toast on top of the shared
controllerRequired chip. Route it through controllerRequired('measure', slot)
and drop the toast; vr-measure-iwer H asserts the chip at that hand and no toast.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading import.meta.env whole made vite inline every VITE_ key (CSP script-src, peer host, ...) into three chunks, and an exported game zip carried them. Literal key reads in errorReports, perf beacon, meshy, playOrigin, cloudPlugin. export-zip now greps the zip's HTML for an injected beacon TAG (not the URL) and fails on any inlined env object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- one job took 53-73 min against its 75 min limit; release.yml's run for 1.45.0 timed out with three perf-budget runs started by one tag push - the push / PR / release.yml triggers now run the --part 1/3..3/3 matrix deps.yml already used (~20-25 min a part); deps.yml's per-part calls are unchanged; per-part limit 50 min - no required check names the job (only deps-gate / pc-battery on deps) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… ran Scene's click rule (moved <= 5 px and pointerdown -> pointerup under 400 ms) read Date.now() inside both handlers, so on a loaded page (the unfolded N6 under software GL, a gizmo grab on a big scene) a slow frame or a heavy pointerdown handler between the two made a quick finger tap read as a long press and the select / deselect was dropped. Both ends and the double-click window now use the input's own timestamp (performance.timeOrigin + event.timeStamp, still on the Date.now() clock so VR picks compare against the same epoch). select-41's G14 recorder logs both clocks beside the gizmo state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…80 s (54 X10)
Since the scripts moved into the sandbox guest, globalThis.__slowRuns was the
guest's global, so the page always read 1; and { timeout: 180000 } sat in the
arg slot of waitForFunction, so the wait ended at the 30 s default. On a
~4 fps runner the 30 slow runs plus the runaway node's per-frame loop limit
take longer than that: red on CI since 1.44.0. The counter now rides the
target box's position.z, the options are the third argument, the runaway
node is removed before the section, and the label carries runs + seconds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… out of quarantine (54 X11) The third peer's "C received the scene" read C's count after a fixed wait and was red on CI and under load with C partway (1/3/4 of 5). It now waits for A to have received C's getobjects (premise), then polls up to 90 s comparing C with A's current count; a red carries the C/A trail over time. A's five boxes are polled instead of a 1 s wait, and "C holds open conns" is bounded at 60 s. On a GPU host the trail shows C at 0/5 and 4/5 for up to 12 s before 5/5 (3/3 green), the window a fixed read raced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inger up A busy page dispatches a 60 ms tap 600 ms late: Input.dispatchTouchEvent sends touchEnd 600 ms after touchStart, stamped t0 + 60 ms (t0 from the browser's clock, since a pc slot's browser is another machine). A busy loop inside the page cannot stage this, because CDP acks touchStart only once the page is idle. A premise check asserts the handlers ran > 450 ms apart while the input says < 400 ms. Counterfactual: red 2/2 on v1.45.1 (handlers ~633 ms apart, the tap is dropped), select-41 58/0 x2 on the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The four unfolded-N6 checks were quarantined for a tap voided by a long frame between its pointerdown and pointerup handlers (0cfd251 times it by the events now), and for the tap that lands on the seated gizmo and leaves the box selected. Green in 6 of 6 runs on the fix: pc x4 and Deck local x2, 58/0 each. The new long-frame check (dfe82e2) is red 2/2 on v1.45.1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s window, out of quarantine Traced under load ~20: Accept -> the 'Backup before' save took ~10 s and the replicated clear landed ~15 s after Accept, so the 15 s window read a running load as 'nothing happened'. Removes the quarantine entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # src/components/Scene.svelte
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Quest error 'Cannot read properties of null (reading getViewerPose)' came from @threlte/xr's headset task calling xr.getFrame().getViewerPose() when three has no frame (after the session ended). A small vite transform (scripts/guard-threlte-xr.cjs) adds the null guard there and in the hit-test task; @threlte/xr is served as source so dev gets it too. The app's own XR frame callbacks were already guarded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An unhandled rejection with a non-Error reason used to reach a report as String(reason) - the opaque 'Ma' from iPad Chrome. describeReason (pure, errorReportCore) now says 'Non-Error rejection (<constructor>): <json>' with a depth-2, key-capped, 140-char JSON whose long strings are dropped and which still goes through the message scrub (urls, emails, ids, quoted phrases). An Error with no stack leads with its constructor name. The window error seam and the diagnostics ring use the same description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cancelPull freed the buffers and failed the row, but never told the sender, and a file that started (or a single-shot answer that came) after the cancel opened a fresh transfer and landed in the Library anyway. Cancel now asks every peer it asked to stop (volcancel -> stopSendingTo, the session-volume Cancel's message) and refuses a late start, a late whole file and a last slice still being checked, until a new ask or 45 s. Unit libraryPullCancel: the real pull path over a stalling fake transport (4 of 6 red on base). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
App.svelte probes for a WebGL 2 context before mounting threlte's Canvas (the probe context is released at once). Without one it shows NoWebGLScreen (what to try: hardware acceleration, update the browser, another browser; Help link to the docs; Reload) instead of a blank page, and sends ONE 'webgl' report. The reporter files every WebGL create failure (three's wording, the browser's, the probe's) under one message and a frame-free signature, so the window error + rejection pair the old boot produced dedupes to one. e2e no-webgl (added to the battery). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The roadmap-78 repro (limit 30, start, pause 6 s, resume => lost "Out of
time") was not kit.round's clock: the research run's own data shows the
round ended exactly 10.0 s of wall time after go, the length of the
starter Countdown behaviour the lab scene still held. Its this.after()
timers ran on the session clock straight through the pause and called
kit.round.lose('Out of time').
Behaviour timers (method and closure) now count play time: while the
game singleton (or kit.round) is paused they hold, and on resume every
pending timer moves on by the pause's length (replicated, so a handover
agrees); a timer set during the pause counts from the resume. The host
seam is pausedSince(), shared by the app and the logic sim.
Tests: sim/behaviourPause (red on base), kitRoundPauseApp (the round's
own clock on the app runtime path), e2e round-pause-behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nodesync join hold (fix-agenttest 5) was timed from a peer's FIRST nodesync. A peer whose graphs were empty at the join sends no snapshot and no nodesync (count 0 is never broadcast), so its first nodesync came minutes later with its first object graph, and that real change was held 15 s as if the join were still on; with two more 10 s rounds the graph reached the peer after ~26 s (measured on a cloud build). The host side never asks a joiner for graphs at all, so it had no snapshot to wait for in the first place. noteNodeSyncHandshake starts the window when the link opens (sendHandshake) and again at the handshake's getnodes (a share-or-stash decision can defer it); a nodesync that beats both still starts it, so a join is still not drift. Measured on a cloud build (VITE_CLOUD_PLUGIN, serve-build), first store-only object graph host->peer: 26.5 s before, 9.1 s after (now bounded by the 10 s nodesync round). timeline suite on the cloud build: ALL PASS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A taken sleeve ghost now starts at ghost size on the taking hand and grows to true size (times the world's scale) as that hand moves 6 to 40 cm from the sleeve wrist, pushed out along the hand's ray so it never covers more than about 50 degrees of the view. Full size latches with a detent pulse; after the latch the grip-move sticks drive it through grabStickAdjust/axesForSlot (Y reels, X scales). Back within 10 cm of the wrist (or a release before the latch) cancels: the preview shrinks and flies back into its slot (instant under reduced motion). Placement converts the preview's world size into objectsGroup scale, so a miniature world gets a true-size object. Grip with the other hand at a slot (< 4 cm) is a direct take, claimed before any grab or the V5 world grab; trigger/pinch on the ray is a distance take, and a pinch at a slot takes too. A long pinch a hook claimed no longer toggles the radial menu on release. Pure maths in vrSleeveMath.js (unit tested); the frame path reuses scratch vectors. New IWER suite vr-sleeve-iwer (grip/trigger/hands, miniature world). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ide screen On the OPPO Find N6 unfolded (770 px) a docked Connect bar pushes the top-right cluster (notes, bell, people, profile circle) down to 62..114. 76-int cleared only the profile circle and only for the AI window, so its header still sat 2 px under the bell row, and the Debugger and every module toolbox (top 76) opened with their headers under the cluster. dragWindow's top floor is now ONE rule for every window: windowSize.TOP_CHROME (Connect pill/bar, #hud-tr, #avatar-trigger) through the pure topChromeFloor, which replaces the Connect-pill check and the AI window's clearAvatar opt-in. Tests: tests/unit/topChromeFloor.test.js; connector-window N6 checks that no window header (AI window, Debugger) sits under the top chrome (red on base: "ai-assistant-window top 112 under #hud-tr"). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n-in button Signed out with a provider of your own, the AI window's header carries "Sign in to connect" (76 FW-AI); on the folded N6 sheet (390 px) that cut the title to "AI assist…". The header now measures its own width (container query) and below 440 px the button reads "Sign in"; its accessible name and tooltip stay "Sign in to connect". Test: connector-window N6 checks the header title is not cut short and the button keeps its name (red on base: folded title scrollWidth > clientWidth). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A tab open across a redeploy (or a dropped fetch on a phone) failed lazy imports silently. A build-only vite transform (scripts/import-retry.cjs) splices one retry into vite's preload helper, which every lazy import goes through; src/lib/chunkReload.js does the retry (400 ms) and, when it fails too or a chunk failure reaches vite:preloadError / an unhandled rejection, shows ONE sticky 'A new version is ready - Reload' toast. It never reloads by itself (no loop). Error reports file every chunk failure under one message and a frame-free signature. e2e stale-chunk on a built app (battery: SKIPs on a dev server). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ee about the authority 1.48.1 sent a shared Set Variable to one writer, the kit authority, which applies each event (rid) once. But the authority is each peer's own reading (physics initiator, kit document writer, open links): while two peers read it differently - a stale initiator after a VR peer's run, a roster or mesh not caught up - each sent the press to a different peer, both applied it, and the second applied it on top of the first one's write: Add 1 counted twice and a Set t = NOT Get t toggle flipped back, while a set-to-a-value button looked fine. The rids now travel in the game singleton (last 32, unioned on merge), and an event whose rid is in the state is never applied again by anyone. Unit gameVarOp (4 new, red on base). e2e toggle-peers: 2 peers, 2 peers that disagree about the authority, then 3 peers, a press on every peer (On Click NOT-toggle, HUD button NOT-toggle, Add 1, Latch value): red on base in the disagreeing rounds (t back to 0, k +2), all green after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and unfolded The welcome (Connect Claude + your own provider) was ~560 px of content in a 440 px window (a half-height sheet on the folded N6), so the own-provider card sat below the fold inside an inner scroll. While the welcome shows, the floating window takes its content height (capped by the room below its top, so it still scrolls only when the screen truly is too short), and on a phone the AI sheet asks for the full detent through the new phoneShell.phoneFirstDetents (local, never saved) — a height the person chose still wins. Tests: connector-window N6 (folded + unfolded + unfolded light) checks the welcome has no inner scroll and the own-provider card is inside the window (red on base: scroll 561 > 325 folded, 470 > 321 unfolded); tests/unit/phoneFirstDetent.test.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ot reproduce) Two peers; a painting made the agent's way (Plane + a library image as map) deleted by hand and by the AI tools' delete_objects on either peer, and at agent speed (made, textured and deleted in one go). After each, on both peers: out of the scene graph, no mesh still drawing its picture, and the receiving peer disposed the texture. All green on the 54-int base, so the owner's take (1.51, VR and PC) is not reproduced; the suite stays as the regression proof. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rom the add menu At a real frame rate (node-ux-keys on a GPU), Shift+A → Enter → Space → Enter added two nodes and left focus in an OLD node's number field, so M typed "m" instead of muting (and H, Q, E, arrows, ? after it). rememberFocus treated the first menu's filter input — the newest, vanished focus-trail entry, under 3 s old — as a vanished opener and walked the trail back to the last field you had clicked. A vanished opener is now never a typing field, and the trail fallback never lands in one (keyScope.isTypingField, one rule): focus moves into a field only when you press it. The "Something went wrong: ResizeObserver loop completed" toast: ContextMenu re-placed itself INSIDE its ResizeObserver callback, and once you type the search list caps its own max-height there — the box resized in its own callback, leaving minimalScroll's observer on the same box undelivered (traced by wrapping ResizeObserver per observer: ContextMenu place + minimalScroll on .ctx-scroll). The re-place now runs on the next frame. Tests: tests/unit/rememberFocusTyping.test.js (red on base); node-ux-keys gains "keyboard not in a text field after adding" + "no ResizeObserver loop" (red on base at GPU: focus in n1's field, 2 loops; green on the fix with GPU and with SwiftShader). Green at a real frame rate now, so it leaves battery desk.software. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phones and the Quest browser have no drag and drop, so the Explorer now offers "Add files…" (a real file picker) in the background menu, a folder's menu, a mount's menu and a mounted folder's menu, plus a button on the empty view. The picked files take the SAME route as a drop: onDrop's body became routeIncomingFiles(files, folder), shared by both (mounts buffer, packs take zips, scene views refuse, duplicates ask). "New file ▸ Script / Note / JSON / Text" creates a text file from the Code tab's codeFilesCore templates (a Text template joins them) through codeFiles.createCodeFile, disabled for viewers. A button inside the grid keeps its own Enter/Space (the grid's Enter used to swallow it). New suite explorer-add-files (desktop + phone, dark + light). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Possess drove an object with tank controls and had no way off the ground. Space or a gamepad's A now hops the possessed object: a kinematic hop (possessJump.js, a leaf) that reaches Jump height (default 1.2 m, 0 = off) under the scene's gravity and lands exactly on the take-off height; one hop at a time, the press is an edge. The landing pose is always sent to peers. Possess also reads the gamepad's left stick now (it read only keys and the VR stick). VR is not wired: possess releases on entering VR. The Possess Object node gets a Jump height param, and its node doc and the SDK doc list the controls. Tests: unit possessJump; e2e possess (Space -> the body leaves the ground and lands). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reproduced on the real applyWander (what flowRuntime runs per frame): a group placed at y 0 with the node's defaults bobs within ry 0.3 (y -0.19 at t 0 rising to +0.05 at t 10 s), and a 0.2 m ground slab wired as the area pulls the wanderer to the slab's middle (y -0.1, half sunk). A new "ground" toggle keeps the height the object was placed at while x/z still wander, with or without an area. New Wander nodes start with it on; a saved node without the key keeps its 3-D drift (the aquarium fish). The node doc says when to switch it off. Test: unit wanderGround (3 of 4 red on base). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he arch New check 3.6b: after Start, the module's spawn must be more than 1.7 m (the plinth's 1.4 m half-width + 0.3) from the entrance plinth's centre. Red on the published scene (0.00 m: the arch was centred on the spawn), green on the scenes fix (scenes c56e3e6 on fix/54i-dungeon-spawn, 2.50 m). Point the suite at a scenes worktree with DUNGEON_REALMS_TPSCENE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nish) three bakes renderer.shadowMap.enabled into each program and does not re-check it per draw. setShadowMapEnabled is now the one writer (lightParams + environment) and marks every material for update on a flip. Suspect from the play sub-agent's diag7-9: member floor clones warmed while kit-instancing turned shadows off stayed missing from the canvas until material.needsUpdate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onger vanish)" This reverts commit a422157.
…(row u, cause not proven) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lines the env object 1.54's funnel.js used import.meta.env as a value, which made vite inline the whole env object again (export-zip red on the 1.54.3 preview: 'VITE_APP_ORIGIN:' in the zip's code). A unit guard now fails on any bare import.meta.env in src/ (red on the old line). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… catalog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ers; state_unsafe_mutation in session-volume) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… accepts a window held below the top chrome on a tablet-wide screen (54 f); sheet-handoff tests hand-off only on a list long enough to absorb it (Explorer empty state + Add files overflows a short sheet by ~40 px) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stability patch 1.54.3 on v1.54.2 (integrator 54-int). Union of:
Each fix has a counterfactual test (red on the base, green after). Gates on 4822406: vitest 3717/3717, svelte-check 278/39 = baseline, check:tokens clean, build rc=0. Preview: https://preview-1-54-3.theprototype.pages.dev. Full battery (GPU queue) + release proof follow; CHANGELOG 1.54.3 is in.
🤖 Generated with Claude Code