Skip to content

Release 1.44.0 — Quick wins (roadmap 60) - #476

Merged
AlexZ005 merged 119 commits into
mainfrom
feat/60
Oct 25, 2026
Merged

AlexZ005 merged 119 commits into
mainfrom
feat/60

Conversation

@AlexZ005

Copy link
Copy Markdown
Collaborator

Release 1.44.0 — Quick wins: play from where you stand, trace over a picture, share files in, embed anywhere ⚡ (roadmap 60).

The 60 union (feat/60): #431 #433 #435 (Play here, reference images, share target + file handler, oEmbed hooks, fast
channel, asset cache), fix-live #448, pipeline-1 #441, test-health-1 #442, origin/deps, and the orchestrator add #474
(scatter-sync: room edits held for an approved joiner's dial-back). Integration fixes on top (60-int):

  • Use as reference on a shared image; a toast when there is no scene view yet.
  • F-5 Remove holds in a 3+ peer room (a third peer's roster relay or hosts mesh-fill no longer brings the removed peer back).
  • relink: a drop only one side noticed heals both ways (the side still holding the dead link adopts the fresh conn
    and re-syncs); suite net-relink, counterfactual red.
  • Suite updates for the new Play here entry, Storage settings tab, fast-channel poses, F-3's 4 s ICE grace (net-drop),
    F-4 static AI objects (ai-flow-physics), the lock fixture, and two test-made failures (launch-inbox fixture PNG,
    material-presets-big send counter).

Proof: gates (build, vitest 2770, svelte-check ratchet 287/39, tokens/storage/zindex, scene-lint), battery vs v1.43.0
baseline (new reds A/B'd: pre-existing on v1.43.2 or fixed), preview-1-44 proof (145 rows) + reruns on the final build,
two-peer suites for #474. Known and pre-existing on production 1.43.2 (A/B'd, not
fixed here): the CSP blocks the basis transcoder's eval (ktx2-twins, export-presets, code-popout); deployed-build
net-drop and material-presets-big delivery under load. CHANGELOG.md has the 1.44.0 section.

🤖 Generated with Claude Code

AlexZ005 and others added 30 commits October 23, 2026 15:38
…nel for pose streams

- fastChannel.js (leaf): a negotiated {ordered:false, maxRetransmits:0} data channel on each
  PeerJS connection's own RTCPeerConnection (id 7, no extra signaling), opened only when the
  other side advertises `fc: 1` in the modules handshake + a `fastchan` hello down the same conn
- every pose message (camera, vrhands, move) carries `ps`, one monotonic counter per sender;
  receivers drop a pose older than the newest applied for that (sender, key) — on both channels
  and inside batch envelopes, so a late streamed move never overwrites the committed one
- trailing keyframe: a stream's last pose is re-sent reliably (same ps) once the key goes
  quiet for 250 ms, to the peers that got it unreliably
- streams marked fast: avatar camera (not when its extras change), VR hands (not on a rep
  switch), gizmo drag, physics bodies, VR held objects (not the release), play-mode grabs,
  possess rides; everything else stays on the reliable conn
- graceful fallback: older peers / closed channel / >12 KB messages go reliable; kill switch
  safeStorage fastChannel=off; `fastchan` on the cloudHooks ALWAYS_ALLOWED floor
- debug hook __stores.fastChannel (links, stale filter, keyframes, pose tap for the loss e2e)
- unit: tests/unit/fastChannel.test.js (18)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- manifest: share_target (POST multipart `files`: images, glb/gltf, tpscene), file_handlers
  (.tpscene, .glb, .gltf → /), launch_handler focus-existing
- static/sw.js: receives the share POST (a static site has no server), parks the files in
  the `tp-share-inbox` cache and 303s to /?shared=<n>; everything else is still a no-cache
  passthrough
- src/lib/launchInbox.js: reads the inbox ONCE (cache deleted, ?shared= stripped) and takes
  launchQueue file launches; routes .tpscene → open (Sidebar Load path), models → import
  into the current scene (companions ride along), lone images → Explorer Library + "Show in
  Library"; waits for the scene group AND the restore-session answer first
- autosave: restoreSettled() — resolves once the boot's restore question is answered
  (no snapshot / non-empty / auto-restored / Restore finished / Dismiss)
- tests/unit/launchInbox.test.js (14): manifest keys, the real sw.js in a fake worker scope
  (park + 303, text-only, replace, passthrough), the worker → app round trip, classifier

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…r a cap

- assetCacheCore.js (zero-import leaf): url keys (+ a version tag for build-bundled files),
  derived keys (source hash + kind + settings, field order irrelevant), the index shape and
  its normalizer, usage (a shared blob counted once), the LRU eviction plan, orphans
- assetCache.js: one blob per SHA-256 in OPFS (tp-asset-cache/blobs) + index.json; the same
  model on CacheStorage where OPFS cannot write; a plain fetch where neither exists. Reconciles
  orphan blobs / missing blobs on open; index flushed on a 400 ms debounce and on pagehide
- kinds wired: pack files (packCache.js is now a url-keyed view over the cache, same API; 39 P5's
  CacheStorage copies are migrated once and that cache deleted), bundled skies (hdriRuntime,
  keyed by the build version), CC0 downloads (cc0Fetch.fetchBytes), converted textures (the
  import optimizer's output keyed by source hash + options + version), pack anim refs
- navigator.storage.persist() asked once, from a toast with the reason, the first time something
  is cached (assetCache:persistAsked); never on boot, never again
- never the app shell: only content urls reach it
- unit: tests/unit/assetCacheCore.test.js (13); place-drag-cache reads the store through
  packCache.cachedPackBuffer instead of CacheStorage

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uites

- Settings ▸ Storage (StorageSettings.svelte, Workspace group): what the cache holds by kind,
  Clear, the size limit (256 MB / 512 MB / 1 GB / 2 GB, LRU), the persistence state with
  "Ask the browser", and the Storage breakdown button
- Storage breakdown: a "Cached downloads" category (skies, converted textures, downloaded
  files), one row per kind, reclaimed through the cache's own delete
- e2e: asset-cache-opfs (second load served from OPFS with no request, persist asked once,
  no shell in the index, Settings Clear, the 39 P5 migration), fast-channel-loss (p95 pose gap
  at 0/5/10 % loss before/after through a WebRTC loss shim), fast-channel-fallback

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ngs the view back

The player starts where the editor camera is: X/Z under it, the feet on the first solid
surface straight below (scene meshes on the shared BVH trees, then the physics ground
plane; hidden objects, sensors, water and reference images do not count), facing the
view's heading. Nothing below → the scene's spawn; no spawn either → the camera's eye.
A session-only override that currentSpawn() returns first, so desktop Play, the VR
walker, api.respawnPlayer and the game shell all honour it for that round; leaving Play
clears it and restores the editor camera, its orbit target and the selection.

Entry points: Ctrl+Shift+Enter, a row in Play's right-click / phone long-press menu, an
optional toolbar roster button (Customize), phone More ▸ Tools & View, the viewport
menu's Tools, and the VR radial Tools ▸ Play here / Back to edit (Interact from where
you stand; Edit restores the exact reference space and world grab).

Height follows the scene's locomotion: desktop Play is grounded by default (37 R24 pins
the eye), and the VR walker stands on real surfaces only while a simulation runs.

Tests: unit playHere (the spawn raycast through a real three scene), e2e play-here
(desktop + phone N6 folded) and play-here-iwer (IWER, applied-offset spy).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rop menu (untested)

underlays.js (LOCAL per scene in IndexedDB; Share with session = underlay /
underlaydelete / getunderlays, owner-only rows, ROOM_SCOPED, request on the floor,
validated), UnderlayLayer (under the world rig, outside sceneObjects, on the editor
helper layer, hidden in Play/Interact, no-op raycast), UnderlayWindow (opacity, size,
height, ground / facing the view, share, remove) + the image-drop 'Use as reference'
menu, viewport Tools rows. Viewport/room thumbnails now render without the helper
layer. NOT yet run: svelte-check ratchet after the type fix, the underlay e2e suite.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Share POST through the real service worker (image -> Library, .glb -> scene),
the restore rule, CDP manifest/installability, launchQueue file launches.
Not yet run green: the first run timed out waiting for a slot.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…of queueing it stale

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- a lone shared image no longer pulls in fileHandler (a cold dev-server compile stalled it)
- loadExplorer() before importFiles, so the index write cannot replace an unloaded library
- a failed route records the error and toasts it; lastLaunch.stage for diagnosis
- suite: --ignore-certificate-errors (SW script fetch on the self-signed dev cert),
  poll with until() instead of an async waitForFunction predicate, wait for the level name

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… grid, build-safe store cast, suites

Completes the Q5 WIP (7585d83). Fixes found by the new suite: each image's
block in Tools ▸ Reference images was a single 36px cell of the toolbox body's
button grid, so every slider measured 0px wide (now grid-column: 1 / -1, the
.tbx-row rule); the $peers JSDoc cast inside a chain (which breaks the rolldown
build) is typed through its own $derived. debugHooks gains underlays +
underlayPose.

Tests: unit underlays (normalizer + aspect, 6); e2e underlay (39, ALL PASS):
image-only drop → Use as reference on the ground; plane outside sceneObjects on
the helper layer; a ray through it misses (an identical plane hits) and a click
selects nothing; opacity slider drives the material; the live render shows it,
the viewport thumbnail does not; hidden in Play; GLTF export + .tpscene payload
carry none of it; B sees nothing until Share, then follows A's opacity
read-only, unshare drops it; reload keeps it; a later joiner gets it from the
full-state reply; Remove takes it from everyone. npm run build green, ratchet
299/39 = baseline, unit 2512 green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…h pages paused, edits read from .text, a cadence check per phase

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…al pose land (10 % back-off outlasts a fixed 1.5 s)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…r message swapped same-ms releases), ordered-channel control check

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Conflicts with 1.42 (roadmap 50), both sides kept: PhoneShell (AR table + Play here imports/items),
cloudHooks floor (getytext + getunderlays), debugHooks (arTable + playHere/underlays/underlayPose),
peerScenes ROOM_SCOPED (ytext/ytextaw + underlay/underlaydelete), wireValidate (ytext validators +
underlay validators), phoneBar VIEW_ITEMS (… 'ar', 'playhere') + its unit test, vr/modes (arTable
import + playSpawn/playHere imports; editorMode subscriber ends a VR Play here off-session, then the
AR-table early return). sessions.viewportThumbnail keeps 50's withCleanView, which already switches
the helper layer (where underlays live) off — 60's separate mask save/restore dropped as redundant.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…reated

Viewers' creations stay local and their edits are dropped by every receiver, so
executeAiTool answered { created } for work nobody else would see (test flight T1).
Scene-changing tools now return a view-only refusal; list_scene and local
simulation playback still work.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…sts Connection error

- ICE held 'disconnected' past 5 s closes the conn ourselves, so a peer that died
  without closing its channel goes through the reconnect window instead of
  staying a ghost (test flight T5).
- A redial answered 'peer-unavailable' is not toasted; three answers in a row end
  the window at once. The id is read from the end of the message (the old regex
  answered 'Could').
- Peer-level webrtc/disconnected noise right after a leave, drop or redial is
  logged, not toasted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…etting shows on Connect

- Every auto-admitted peer gives the host a toast AND a notification-history entry
  that keeps its buttons until answered: Remove (session-local door: roster row
  dropped, link closed, re-dials refused while the tab is open) and the provider's
  Turn off (test flight T14: a remembered 'Allow guests' admitted silently).
- authProvider.admitNotice(peerId, cloudMeta) supplies the line + switch-off;
  cloudApi.setConnectBadge puts e.g. 'Public · guests join' on the Connect pill.
- OPEN-CORE.md documents both seams.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…gerprints, release baselines, flake log, coverage guard

scripts/ci/battery-desk.cjs runs tests/e2e/battery.json the way an integrator does (one half per e2e
slot, the self-hosted / production-host / modules-flight cases from data), reruns every red once at the
end of its half, fingerprints each failed check, saves a per-tag baseline and diffs a union run against
it (pre-existing / flaky / NEW). battery.json gains modules, desk and exclude; the 1.43 battery's extra
suites join as optional on runners. tests/unit/batteryDesk.test.js: every e2e file is listed or excluded.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A connected pill collapses to its chip, which is exactly when a host forgets a
remembered 'guests join' setting; the badge was gated off there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tems)

cloudApi.setPeerMenuItems([{id, label, run(peerId, {name})}]) appends up to 8
entries under Mute voice when a peer is right-clicked in Users; the cloud
plugin's 'Report…' rides it. Inert with no plugin.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…isten on ::1 only); BATTERY_COMMIT names a snapshot

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… sub-entry of CLAUDE.md with its line

CLAUDE.md is ~7,000 lines and an agent is shown only its start; the index (generated by
scripts/claude-index.cjs, checked by tests/unit/claudeIndex.test.js) is what to grep first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… desk run, so it can be diffed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the host

Plans review #5 (roadmap 49 follow-up): the last three get* requests off the
cloudHooks ALWAYS_ALLOWED floor, so a cloud viewer's Explorer never filled in and
a shared texture or big material preset stayed missing. Requests only; their
replies stay gateable. A unit test now walks every get* the dispatcher answers;
gettransport, getgame, getkitentities and getpatch are still off the floor and
listed there for a separate look.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…physics

The Add menu stamps standard primitives dynamic (mass 1), so a scene an AI built
from boxes fell apart the moment Play started a sim (test flight T8).
create_objects now writes static through setPhysicsFor (replicated, undoable)
unless an object asks physics: 'dynamic' or a mass; the schema and set_physics
description say so. The Add-menu default is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…{keep})

showToast(message, actions, { keep: true }) (and cloudApi.toast) leaves the
buttons on the notification-history entry until one is pressed — the role offer
sat there as 'Accept?' with nothing to click. Plain action toasts are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…it archive + .env + certs + the desk tool

A v1.42.0 archive without the gitignored .env ran on the public PeerJS cloud: 67/228 suites red on the PC
slot (two-peer 'could not fill the peer id'), no boot at all on the Deck.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AlexZ005 and others added 21 commits October 25, 2026 13:32
… reach them

broadcast skipped a conn that was not open, so everything the host did between
approving a joiner and the dial-back opening (15 s on a throttled run) was dropped;
the joiner only converged if its full-state request was answered later, through the
slow GLTF reply (+24.6 s measured: the scatter suites' 'B has the terrain' on GitHub).
The host now holds room-scoped broadcasts for a peer in approvedDialBacks (bounded:
300 messages / 120 s, a leaf with unit tests) and flushes them, re-gated, after that
conn's handshake. Counterfactual: e2e dialback-sync, red on v1.43.2, green here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…imum); E2E_LONGTASKS logger

On a GitHub-speed runner the approval dial-back opened 15 s after approval, past the
fixed 9 s settle, so a suite's first edit raced a negotiating conn. connect() now also
waits (bounded 45 s, never failing) until both ends hold an open conn. E2E_LONGTASKS=<ms>
prints main-thread tasks over that length, to tell a hung click from a slow one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… (h.eventuallyAfter)

On a GitHub-speed runner a two-peer page renders a frame every 1.5-2.5 s (E2E_LONGTASKS,
CPU x2), so B dispatches A's messages long after A sent them and fixed 10-15 s windows
went red with nothing lost ('B paints at 256 too'). h.caughtUp sends A's ordinary clock
ping to B and waits for B's pong: on the ordered conn that is the moment B has dispatched
everything before it (capped 120 s, says so if not). Each check keeps its own window,
measured from there, so a lost message is still a red.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ys cancelled (#468)

* [docs] deps-auto 3g: pc-battery — PC_BATTERY_WRAP has to be quoted in a systemd unit

Unquoted, Environment=PC_BATTERY_WRAP=e2e-slot --exclusive ... is split at the spaces (found
installing the timer on the desktop).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2j: shards balance on the median runner time of runs 5-10 (16 shards; replayed slowest shard 49 -> 35-38 min)

- refresh --results is repeatable and takes the median per suite: a suite's time moves by half
  between runs on a shared runner, and the 15-shard split fitted to run 9 alone put run 10's
  shards anywhere from 21 to 50 min
- battery.json seconds from runs 5-10 (required + optional passes); replaying runs 8 / 9 / 10 on
  the new split: max shard 38 / 37 / 35 min (was 49 / 38 / 49)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2k: battery only where it tests something; optional set by hand

- deps-policy.cjs: new `battery` output = the PR moves the root app's npm packages and is not a major
- deps.yml: perf budget + plan/e2e only when battery=true (Actions, tools/agent and majors get ci.yml alone);
  a major's deps-gate fails on purpose ("not tested here"); the optional set runs on workflow_dispatch only
- why: Dependabot's first round after 1.43.0 opened 9 PRs at once = ~380 jobs on the account's 20-job cap,
  queueing the v1.43.0 release job and every lane's CI for hours (runs cancelled, re-run after this)
- RELEASING.md + depsCi test (9/9); check-ratchet 299/39 = baseline; actionlint clean

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2l: a cancelled deps run stays cancelled

- confirm / e2e-optional / optional-report / deps-gate used always(), which also runs after a cancel: cancelling
  Dependabot's 9 first-round runs still started their optional sets (18 shards each); now !cancelled()

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2m: three of 51's scatter suites optional on the GitHub runner; medians from runs 5-12

- run 12 (#468, released 1.43.2 app code, CI-only diff) was the scatter suites' first run on the runner:
  scatter-select + scatter-convert red twice (shard + fresh confirm runner: "B has the terrain" never true),
  scatter-sources at the 600 s suite timeout twice (all its checks green until then) -> optional with reasons
- scatter-edit was flaky (green on the confirm runner) and stays required
- refresh --results over runs 5-12 (one durations file per run): 16 required shards ~35 min each

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2n: scatter-edit optional on the GitHub runner too

- run 13 (#468): scatter-edit red on its shard and both confirm tries, the same 'B has the terrain' as
  scatter-select/convert in run 12 (where it was green on confirm); scatter-surface flaky, stays required

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…back queue

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…k to required

GitHub probe (scatter-sync-probe run 40191960730): 'B has the terrain' green on all three
runners, runners 1+2 all green; the slowest runner's reds were all a real click timing out
at 30 s with no main-thread task over 8 s on the clicking page — each input event waits for
a frame ack, and a frame took seconds there. h.PATIENT_CLICK_MS (90 s, E2E_CLICK_MS) keeps
every actionability check and only waits longer. scatter-colliders (optional since deps-auto
run 5) passed on runners 1+2 and goes back to required.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tach, not only the click)

deps-auto run 16 timed out scrollIntoViewIfNeeded ('waiting for element to be stable', i.e. two
frames with one box) before the click at :136. Measured (probe-surface-jank, CPU x2, two pages):
A's frame is ~2.2 s with one sphere idle, the same after the selection opens the Inspector
(no extra canvas, no long task beyond the frame), 2.45 s after Add scatter; the click needs
~13 frames = 28.7 s. A slow runner, not a jank at that click — the overload guard's own rule
(a light scene on software GL is slow, never paused).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…l look gets 90 s; runner estimates

Confirm probe (run 40196033046, three slower runners): select/convert/edit green x3; the rest
were load, not sync. scatter-colliders' drop() sampled stillness on wall time while the step
accumulator catches up <= 8 substeps a frame (30 s wall ~ 1 s simulated on multi-second frames):
each sample now spans 500 ms AND 8 rendered frames, capped at 240 s, and the watcher compares
after a wire barrier. 'A draws the crates' (a local look load) 20 s -> 90 s. battery.json runner
estimates for the six suites set from the probes (they also set battery.cjs' per-suite cap,
3x the estimate, min 600 s, which cut scatter-sources/-colliders off mid-run).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… runners; cap = 3x)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ettings ▸ Storage, poses on the fast channel); battery-snapshot copies quarantine

- vr-radial-menu, phone-bar-42, toolbar-edit-positions ("never Play" no longer matches "Play here"),
  settings-shell (Storage after Explorer): the 60 Q1/Q6 additions.
- avatars-rigged, net-stress: camera/vrhands ride the fast channel between two 1.44 peers — count the
  fast arrivals through fastChannel's pose tap as well as the reliable conn.
- ai-flow-physics prints the tool errors it finds.
- battery-snapshot.sh: battery.cjs requires scripts/ci/quarantine.cjs + tests/e2e/quarantine.json
  (test-health-1) — a base snapshot crashed at load without them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
peerHandler: #474's broadcast shape (an approved joiner's opening dial-back holds room content,
withholdFrom/sendTo shared with the flush) carries 60 Q2's fast-channel attempt and keyframe
bookkeeping inside it; sendReliableTo (the trailing keyframe) re-gates through withholdFrom.
battery.json: the union's optional notes and estimates + #474's dialback-sync and its six scatter
estimates; the scatter-* optional keys removed (scatter-colliders was the one left).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…asks for a dynamic Pebble (fix-live F-4)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…4.0 changelog line for #474

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* [docs] deps-auto 3g: pc-battery — PC_BATTERY_WRAP has to be quoted in a systemd unit

Unquoted, Environment=PC_BATTERY_WRAP=e2e-slot --exclusive ... is split at the spaces (found
installing the timer on the desktop).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2j: shards balance on the median runner time of runs 5-10 (16 shards; replayed slowest shard 49 -> 35-38 min)

- refresh --results is repeatable and takes the median per suite: a suite's time moves by half
  between runs on a shared runner, and the 15-shard split fitted to run 9 alone put run 10's
  shards anywhere from 21 to 50 min
- battery.json seconds from runs 5-10 (required + optional passes); replaying runs 8 / 9 / 10 on
  the new split: max shard 38 / 37 / 35 min (was 49 / 38 / 49)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2k: battery only where it tests something; optional set by hand

- deps-policy.cjs: new `battery` output = the PR moves the root app's npm packages and is not a major
- deps.yml: perf budget + plan/e2e only when battery=true (Actions, tools/agent and majors get ci.yml alone);
  a major's deps-gate fails on purpose ("not tested here"); the optional set runs on workflow_dispatch only
- why: Dependabot's first round after 1.43.0 opened 9 PRs at once = ~380 jobs on the account's 20-job cap,
  queueing the v1.43.0 release job and every lane's CI for hours (runs cancelled, re-run after this)
- RELEASING.md + depsCi test (9/9); check-ratchet 299/39 = baseline; actionlint clean

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2l: a cancelled deps run stays cancelled

- confirm / e2e-optional / optional-report / deps-gate used always(), which also runs after a cancel: cancelling
  Dependabot's 9 first-round runs still started their optional sets (18 shards each); now !cancelled()

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2m: three of 51's scatter suites optional on the GitHub runner; medians from runs 5-12

- run 12 (#468, released 1.43.2 app code, CI-only diff) was the scatter suites' first run on the runner:
  scatter-select + scatter-convert red twice (shard + fresh confirm runner: "B has the terrain" never true),
  scatter-sources at the 600 s suite timeout twice (all its checks green until then) -> optional with reasons
- scatter-edit was flaky (green on the confirm runner) and stays required
- refresh --results over runs 5-12 (one durations file per run): 16 required shards ~35 min each

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2n: scatter-edit optional on the GitHub runner too

- run 13 (#468): scatter-edit red on its shard and both confirm tries, the same 'B has the terrain' as
  scatter-select/convert in run 12 (where it was green on confirm); scatter-surface flaky, stays required

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2o: auto-merge in its own job with contents: write

- #460 (actions, class auto) went green through the gate on the 2k deps.yml, then the gate's auto-merge step
  failed: 'Resource not accessible by integration (enablePullRequestAutoMerge)' (it needs contents: write)
- a separate automerge job after a green deps-gate holds contents + pull-requests write and checks nothing
  out, so the gate (which runs the PR's code) stays contents: read

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2p: battery.cjs run with no --deadline runs every suite

- the deadline was Date.now() + 0, which is truthy, so '|| Infinity' never applied: by hand (no flag) every
  suite after the first came out notrun. CI always passes --deadline, so the workflows were unaffected.
  Found by lane scatter-sync.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2q: scatter-surface optional on the GitHub runner

- red on its shard in runs 13, 14 and 16 (#473 run 16: shard + both confirm tries): the Add scatter click
  times out (locator.click 30 s) - a different failure from the late-joiner terrain race

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2r: knock-physics + env-preset-broadcast optional on the GitHub runner

- the two required suites that fail on their shard about half the time (runs 10-17): knock-physics (shard red
  in 8, 9, 12, 14, 17; run 17 also both confirm tries, '2.3 (premise) B sees the ball parked') and
  env-preset-broadcast (shard red in 10, 12, 13); at ~50% a run loses all three tries ~1 in 8, so each
  alone turned deps-gate red every few runs. The rest of the flaky set is ~25% or less

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…terial-presets-big keeps peerjs's chunked flag

Remove only cut the host's own link: the roster applier unions every relayed userdata and a
'hosts' mesh-fill dials whoever a third peer still holds, so B put C straight back (fix-live
F-5 'Remove drops C' / 'cannot dial back in' red 2 of 3 on the preview). Both now skip
removedPeers. The suite's send counter dropped send()'s second argument, so peerjs re-chunked
its own chunks until the stack overflowed (a test-made page error).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s skipped (#475)

* [docs] deps-auto 3g: pc-battery — PC_BATTERY_WRAP has to be quoted in a systemd unit

Unquoted, Environment=PC_BATTERY_WRAP=e2e-slot --exclusive ... is split at the spaces (found
installing the timer on the desktop).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2j: shards balance on the median runner time of runs 5-10 (16 shards; replayed slowest shard 49 -> 35-38 min)

- refresh --results is repeatable and takes the median per suite: a suite's time moves by half
  between runs on a shared runner, and the 15-shard split fitted to run 9 alone put run 10's
  shards anywhere from 21 to 50 min
- battery.json seconds from runs 5-10 (required + optional passes); replaying runs 8 / 9 / 10 on
  the new split: max shard 38 / 37 / 35 min (was 49 / 38 / 49)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2k: battery only where it tests something; optional set by hand

- deps-policy.cjs: new `battery` output = the PR moves the root app's npm packages and is not a major
- deps.yml: perf budget + plan/e2e only when battery=true (Actions, tools/agent and majors get ci.yml alone);
  a major's deps-gate fails on purpose ("not tested here"); the optional set runs on workflow_dispatch only
- why: Dependabot's first round after 1.43.0 opened 9 PRs at once = ~380 jobs on the account's 20-job cap,
  queueing the v1.43.0 release job and every lane's CI for hours (runs cancelled, re-run after this)
- RELEASING.md + depsCi test (9/9); check-ratchet 299/39 = baseline; actionlint clean

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2l: a cancelled deps run stays cancelled

- confirm / e2e-optional / optional-report / deps-gate used always(), which also runs after a cancel: cancelling
  Dependabot's 9 first-round runs still started their optional sets (18 shards each); now !cancelled()

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2m: three of 51's scatter suites optional on the GitHub runner; medians from runs 5-12

- run 12 (#468, released 1.43.2 app code, CI-only diff) was the scatter suites' first run on the runner:
  scatter-select + scatter-convert red twice (shard + fresh confirm runner: "B has the terrain" never true),
  scatter-sources at the 600 s suite timeout twice (all its checks green until then) -> optional with reasons
- scatter-edit was flaky (green on the confirm runner) and stays required
- refresh --results over runs 5-12 (one durations file per run): 16 required shards ~35 min each

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2n: scatter-edit optional on the GitHub runner too

- run 13 (#468): scatter-edit red on its shard and both confirm tries, the same 'B has the terrain' as
  scatter-select/convert in run 12 (where it was green on confirm); scatter-surface flaky, stays required

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2o: auto-merge in its own job with contents: write

- #460 (actions, class auto) went green through the gate on the 2k deps.yml, then the gate's auto-merge step
  failed: 'Resource not accessible by integration (enablePullRequestAutoMerge)' (it needs contents: write)
- a separate automerge job after a green deps-gate holds contents + pull-requests write and checks nothing
  out, so the gate (which runs the PR's code) stays contents: read

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2p: battery.cjs run with no --deadline runs every suite

- the deadline was Date.now() + 0, which is truthy, so '|| Infinity' never applied: by hand (no flag) every
  suite after the first came out notrun. CI always passes --deadline, so the workflows were unaffected.
  Found by lane scatter-sync.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2q: scatter-surface optional on the GitHub runner

- red on its shard in runs 13, 14 and 16 (#473 run 16: shard + both confirm tries): the Add scatter click
  times out (locator.click 30 s) - a different failure from the late-joiner terrain race

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2r: knock-physics + env-preset-broadcast optional on the GitHub runner

- the two required suites that fail on their shard about half the time (runs 10-17): knock-physics (shard red
  in 8, 9, 12, 14, 17; run 17 also both confirm tries, '2.3 (premise) B sees the ball parked') and
  env-preset-broadcast (shard red in 10, 12, 13); at ~50% a run loses all three tries ~1 in 8, so each
  alone turned deps-gate red every few runs. The rest of the flaky set is ~25% or less

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* [fix] deps-auto 2s: automerge runs after a green gate even when the battery was skipped

- #460 on c6dda92: run green (scope auto, ci green, deps-gate + pc-battery SUCCESS) but automerge SKIPPED:
  its implicit success() also checks the gate's own needs, and perf/plan/e2e are skipped for every PR
  without the battery. Now: !cancelled() && needs.gate.result == 'success' && class auto && base deps

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bumps the actions group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4` | `7` |
| [actions/setup-node](https://github.com/actions/setup-node) | `4` | `7` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `4` | `8` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4` | `7` |
| [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) | `2` | `3` |
| [softprops/action-gh-release](https://github.com/softprops/action-gh-release) | `2` | `3` |



Updates `actions/checkout` from 4 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v7)

Updates `actions/setup-node` from 4 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v4...v7)

Updates `actions/download-artifact` from 4 to 8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@v4...v8)

Updates `actions/upload-artifact` from 4 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v7)

Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v2...v3)

Updates `softprops/action-gh-release` from 2 to 3
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](softprops/action-gh-release@v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: dependabot/fetch-metadata
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
battery.json: deps' runner medians and optional reasons; scatter-surface takes the runner's 238 s;
the scatter-* optional keys go after #474 (orchestrator) — knock-physics and env-preset-broadcast
stay optional until green twice on the runner.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
net-drop on the deployed preview lost ONE direction's edits after a heal: one end closed its link
(F-3's ICE grace, or the drop) and redialled, while the other end's conn still read open - a close
never crosses a dead link - so it refused the inbound heal ("the stable outgoing conn stays
preferred") and kept sending, and answering the heal's full-state requests, into a conn nobody
reads. A healed handshake now says `relink` before anything that is answered; the receiver whose
conn still reads open adopts the conn it came on, closes the stale one and re-syncs both ways.
`relink` is on the capability floor (transport, no content).

net-relink manufactures the zombie (higher id: reads open, swallows sends, hears no close; the
lower id closes its end): 9/0 twice; counterfactual without the relink send 6/3 (the zombie is
kept, Z's edits and full-state reply never reach L). fix-live 46/0, dialback-sync 7/0,
fast-channel-loss 32/0 with it; net-drop/net-reconnect red alike on base and relink snapshots
(box load ~19). Battery: net-relink 97 s, optional until a runner has seen it green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant