Skip to content

The graph rides 0.5.1: polyengine#239 closes the checkpoint's starvation of its sibling drivers - #104

Merged
lannbot merged 1 commit into
mainfrom
fix/runtime-0.5-bump
Aug 23, 2026
Merged

The graph rides 0.5.1: polyengine#239 closes the checkpoint's starvation of its sibling drivers#104
lannbot merged 1 commit into
mainfrom
fix/runtime-0.5-bump

Conversation

@lannbot

@lannbot lannbot commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Fixes the field-reported crash (mobile Firefox, Drive testing): driveAsync: a resumed-activation claim was never released.

Both halves of the obvious reading were wrong, and the round's record says so: not Gecko (nine-case JSPI ordering probe: SpiderMonkey ≡ V8), and not network latency (the first diagnosis read its own 4s proxy as causal; the control fires at zero delay — retracted). The mechanism, proven causally on stock 0.4.0: driveAsync's unconditional speculative pending-resumption entry is a store-wide gate, and the device's own two periodic drivers collide with it — the worker's deliberately non-blocking 500ms checkpoint is near-always in flight, the solo page's 1s us-events drain arrives into it and can only hop, and 10k hops later the assert fires. A phone is just where slow OPFS widens the window. Upstream polyengine#239 (in v0.5.1) guards exactly the proven line and adds the driver-arrival wake.

Row 47b measures the starvation itself: checkpoint+us-events storm, 12s. On 0.4.0: 1 drain, then the user's exact trap. On 0.5.1: 108 drains, no trap — the drain recovery specifically exercises the wake, the half a delete-the-line causal test can't reach.

What rode along:

  • A22: the embedder is application-only; the error vocabulary moved to @polyengine/protocol (new pin, 11 files). Pin-comment module-identity reasoning rewritten with was-true-until history (ports couple to protocol now; the one-runtime obligation stands on its own).
  • webrtc sibling → v0.5.0 — the only shape keeping one runtime in the graph and lazy bundling (JSR 0.5.0 re-trips the documented node: bundle hazard). CI sibling pin updated; local sibling checkouts must advance to v0.5.0.
  • wasi/fs mutate-directory tightening: checked against our writable: true preopens — permissive side, no change; recorded because the previous bump's checklist wrongly claimed an empty wasi window.
  • Harness: Firefox gains the persistent-storage pref (persist() never settles headless without it; solo-persistence/storage/gdrive/account-storage all pass under Gecko now) and a recorded Juggler hazard (promising exports from page.evaluate frames SIGSEGV the content process).

Gates: matrix ALL PASS (47b red→green across the bump), e2e 24/24, four bringups, engine check/resume/pair, invariants 9/9, resolved graph = exactly one runtime@0.5.1 + one protocol@0.2.3.

…ion of its sibling drivers

The field report was 'driveAsync: a resumed-activation claim was never
released' on mobile Firefox during Drive testing, and both halves of
the obvious reading were wrong: not Firefox (a nine-case JSPI ordering
probe shows SpiderMonkey and V8 byte-identical on every primitive this
rests on), and not network latency (a first diagnosis read its own 4s
proxy as the cause; the control run fires the assert at ZERO delay).

The mechanism, proven causally on stock 0.4.0: driveAsync's
unconditional speculative pending-resumption entry is a store-wide
gate. The device's own two periodic drivers collide with it — the
worker's 500ms-debounced NON-BLOCKING checkpoint (a recorded design
decision) is near-always in flight, and the solo page's 1s us-events
drain arrives into it and can only hop; ten thousand hops later the
assert fires with the user's exact message. A phone is simply where
slow OPFS widens the window. Deleting the one speculative-entry line
takes the reproduction from 18 firings to 0; upstream #239 (in v0.5.1)
guards exactly that line and adds the driver-arrival wake.

Matrix row 47b is the regression gate and measures the starvation
itself: 12s of back-to-back checkpoint + us-events on one store. On
0.4.0: one drain in twelve seconds, then the trap. On 0.5.1: 108
drains, no trap — the drain count recovering is specifically the
driver-arrival wake, the half a delete-the-line test cannot exercise.

The bump rode A22 (embedder is application-only now): the error
vocabulary — ComponentException, isComponentException, isTrap,
toCloneable, fromCloneable — moved to @polyengine/protocol across
eleven files, and the pin-comment's module-identity reasoning was
rewritten for the new shape (ports couple to the protocol package, not
the runtime; the one-runtime obligation stands on its own). The webrtc
sibling advances to v0.5.0 — the only resolution that keeps one runtime
in the graph AND the lazy-bundling property (JSR's 0.5.0 re-trips the
documented node: bundle hazard; the CI sibling pin follows). wasi/fs's
in-window mutate-directory tightening lands on the permissive side of
our writable:true preopens — checked, not assumed, since the previous
bump's checklist wrongly claimed an empty window.

Harness, from the same investigation: Playwright Firefox gains the
persistent-storage pref (navigator.storage.persist() never settles
headless without it; four more scenarios now pass under Gecko) and a
recorded Juggler hazard (promising exports called from page.evaluate
frames SIGSEGV the content process — Firefox-lane scenarios drive
through page scripts).

Gates: devstore matrix ALL PASS with 47b red-then-green across the
bump, e2e 24/24, all four bringups, engine check/resume/pair,
invariants 9/9, resolved graph exactly one runtime@0.5.1 and one
protocol@0.2.3.
@lannbot
lannbot merged commit 6acf24d into main Aug 23, 2026
3 checks passed
@lannbot
lannbot deleted the fix/runtime-0.5-bump branch August 23, 2026 21:01
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.

2 participants